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 (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 (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 (TRUE, &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 (TRUE, 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;
1840 guint32 vtable_size, class_size;
1843 gpointer *interface_offsets;
1845 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1846 mono_domain_lock (domain);
1847 runtime_info = class->runtime_info;
1848 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1849 mono_domain_unlock (domain);
1850 mono_loader_unlock ();
1851 return runtime_info->domain_vtables [domain->domain_id];
1853 if (!class->inited || class->exception_type) {
1854 if (!mono_class_init (class) || class->exception_type) {
1855 mono_domain_unlock (domain);
1856 mono_loader_unlock ();
1858 mono_raise_exception (mono_class_get_exception_for_failure (class));
1863 /* Array types require that their element type be valid*/
1864 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1865 MonoClass *element_class = class->element_class;
1866 if (!element_class->inited)
1867 mono_class_init (element_class);
1869 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1870 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1871 mono_class_setup_vtable (element_class);
1873 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1874 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1875 if (class->exception_type == MONO_EXCEPTION_NONE)
1876 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1877 mono_domain_unlock (domain);
1878 mono_loader_unlock ();
1880 mono_raise_exception (mono_class_get_exception_for_failure (class));
1886 * For some classes, mono_class_init () already computed class->vtable_size, and
1887 * that is all that is needed because of the vtable trampolines.
1889 if (!class->vtable_size)
1890 mono_class_setup_vtable (class);
1892 if (class->generic_class && !class->vtable)
1893 mono_class_check_vtable_constraints (class, NULL);
1895 /* Initialize klass->has_finalize */
1896 mono_class_has_finalizer (class);
1898 if (class->exception_type) {
1899 mono_domain_unlock (domain);
1900 mono_loader_unlock ();
1902 mono_raise_exception (mono_class_get_exception_for_failure (class));
1906 vtable_slots = class->vtable_size;
1907 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1908 class_size = mono_class_data_size (class);
1913 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1914 if (class->interface_offsets_count) {
1915 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1916 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1917 mono_stats.imt_number_of_tables++;
1918 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1921 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1922 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1925 mono_stats.used_class_count++;
1926 mono_stats.class_vtable_size += vtable_size;
1927 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1930 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1932 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1934 vt->rank = class->rank;
1935 vt->domain = domain;
1937 mono_class_compute_gc_descriptor (class);
1939 * We can't use typed allocation in the non-root domains, since the
1940 * collector needs the GC descriptor stored in the vtable even after
1941 * the mempool containing the vtable is destroyed when the domain is
1942 * unloaded. An alternative might be to allocate vtables in the GC
1943 * heap, but this does not seem to work (it leads to crashes inside
1944 * libgc). If that approach is tried, two gc descriptors need to be
1945 * allocated for each class: one for the root domain, and one for all
1946 * other domains. The second descriptor should contain a bit for the
1947 * vtable field in MonoObject, since we can no longer assume the
1948 * vtable is reachable by other roots after the appdomain is unloaded.
1950 #ifdef HAVE_BOEHM_GC
1951 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1952 vt->gc_descr = GC_NO_DESCRIPTOR;
1955 vt->gc_descr = class->gc_descr;
1958 vt->size_descr = mono_gc_compute_size_descr (class);
1962 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1963 if (class->has_static_refs) {
1964 gpointer statics_gc_descr;
1966 gsize default_bitmap [4] = {0};
1969 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1970 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1971 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1972 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1973 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1974 if (bitmap != default_bitmap)
1977 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1979 vt->has_static_fields = TRUE;
1980 mono_stats.class_static_data_size += class_size;
1985 while ((field = mono_class_get_fields (class, &iter))) {
1986 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1988 if (mono_field_is_deleted (field))
1990 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1991 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1992 if (special_static != SPECIAL_STATIC_NONE) {
1993 guint32 size, offset;
1995 gsize default_bitmap [4] = {0};
1999 if (mono_type_is_reference (field->type)) {
2000 default_bitmap [0] = 1;
2002 bitmap = default_bitmap;
2003 } else if (mono_type_is_struct (field->type)) {
2004 fclass = mono_class_from_mono_type (field->type);
2005 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2007 default_bitmap [0] = 0;
2009 bitmap = default_bitmap;
2011 size = mono_type_size (field->type, &align);
2012 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2013 if (!domain->special_static_fields)
2014 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2015 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2016 if (bitmap != default_bitmap)
2019 * This marks the field as special static to speed up the
2020 * checks in mono_field_static_get/set_value ().
2026 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2027 MonoClass *fklass = mono_class_from_mono_type (field->type);
2028 const char *data = mono_field_get_data (field);
2030 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2031 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2032 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2035 if (fklass->valuetype) {
2036 memcpy (t, data, mono_class_value_size (fklass, NULL));
2038 /* it's a pointer type: add check */
2039 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2046 vt->max_interface_id = class->max_interface_id;
2047 vt->interface_bitmap = class->interface_bitmap;
2049 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2050 // class->name, class->interface_offsets_count);
2052 if (! ARCH_USE_IMT) {
2053 /* initialize interface offsets */
2054 for (i = 0; i < class->interface_offsets_count; ++i) {
2055 int interface_id = class->interfaces_packed [i]->interface_id;
2056 int slot = class->interface_offsets_packed [i];
2057 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2061 /* class_vtable_array keeps an array of created vtables
2063 g_ptr_array_add (domain->class_vtable_array, vt);
2064 /* class->runtime_info is protected by the loader lock, both when
2065 * it it enlarged and when it is stored info.
2068 old_info = class->runtime_info;
2069 if (old_info && old_info->max_domain >= domain->domain_id) {
2070 /* someone already created a large enough runtime info */
2071 mono_memory_barrier ();
2072 old_info->domain_vtables [domain->domain_id] = vt;
2074 int new_size = domain->domain_id;
2076 new_size = MAX (new_size, old_info->max_domain);
2078 /* make the new size a power of two */
2080 while (new_size > i)
2083 /* this is a bounded memory retention issue: may want to
2084 * handle it differently when we'll have a rcu-like system.
2086 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2087 runtime_info->max_domain = new_size - 1;
2088 /* copy the stuff from the older info */
2090 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2092 runtime_info->domain_vtables [domain->domain_id] = vt;
2094 mono_memory_barrier ();
2095 class->runtime_info = runtime_info;
2098 /* Initialize vtable */
2099 if (callbacks.get_vtable_trampoline) {
2100 // This also covers the AOT case
2101 for (i = 0; i < class->vtable_size; ++i) {
2102 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2105 mono_class_setup_vtable (class);
2107 for (i = 0; i < class->vtable_size; ++i) {
2110 if ((cm = class->vtable [i]))
2111 vt->vtable [i] = arch_create_jit_trampoline (cm);
2115 if (ARCH_USE_IMT && imt_table_bytes) {
2116 /* Now that the vtable is full, we can actually fill up the IMT */
2117 if (callbacks.get_imt_trampoline) {
2118 /* lazy construction of the IMT entries enabled */
2119 for (i = 0; i < MONO_IMT_SIZE; ++i)
2120 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2122 build_imt (class, vt, domain, interface_offsets, NULL);
2126 mono_domain_unlock (domain);
2127 mono_loader_unlock ();
2129 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2130 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2131 mono_raise_exception (mono_class_get_exception_for_failure (class));
2133 /* make sure the parent is initialized */
2134 /*FIXME shouldn't this fail the current type?*/
2136 mono_class_vtable_full (domain, class->parent, raise_on_error);
2138 /*FIXME check for OOM*/
2139 vt->type = mono_type_get_object (domain, &class->byval_arg);
2140 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2141 /* This is unregistered in
2142 unregister_vtable_reflection_type() in
2144 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2145 if (class->contextbound)
2154 * mono_class_proxy_vtable:
2155 * @domain: the application domain
2156 * @remove_class: the remote class
2158 * Creates a vtable for transparent proxies. It is basically
2159 * a copy of the real vtable of the class wrapped in @remote_class,
2160 * but all function pointers invoke the remoting functions, and
2161 * vtable->klass points to the transparent proxy class, and not to @class.
2164 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2167 MonoVTable *vt, *pvt;
2168 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2170 GSList *extra_interfaces = NULL;
2171 MonoClass *class = remote_class->proxy_class;
2172 gpointer *interface_offsets;
2176 #ifdef COMPRESSED_INTERFACE_BITMAP
2180 vt = mono_class_vtable (domain, class);
2181 g_assert (vt); /*FIXME property handle failure*/
2182 max_interface_id = vt->max_interface_id;
2184 /* Calculate vtable space for extra interfaces */
2185 for (j = 0; j < remote_class->interface_count; j++) {
2186 MonoClass* iclass = remote_class->interfaces[j];
2190 /*FIXME test for interfaces with variant generic arguments*/
2191 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2192 continue; /* interface implemented by the class */
2193 if (g_slist_find (extra_interfaces, iclass))
2196 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2198 method_count = mono_class_num_methods (iclass);
2200 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2201 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2203 for (i = 0; i < ifaces->len; ++i) {
2204 MonoClass *ic = g_ptr_array_index (ifaces, i);
2205 /*FIXME test for interfaces with variant generic arguments*/
2206 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2207 continue; /* interface implemented by the class */
2208 if (g_slist_find (extra_interfaces, ic))
2210 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2211 method_count += mono_class_num_methods (ic);
2213 g_ptr_array_free (ifaces, TRUE);
2216 extra_interface_vtsize += method_count * sizeof (gpointer);
2217 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2221 mono_stats.imt_number_of_tables++;
2222 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2223 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2224 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2226 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2227 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2230 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2232 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2234 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2236 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2237 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2239 pvt->klass = mono_defaults.transparent_proxy_class;
2240 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2241 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2243 pvt->size_descr = mono_gc_compute_size_descr (mono_defaults.transparent_proxy_class);
2246 /* initialize vtable */
2247 mono_class_setup_vtable (class);
2248 for (i = 0; i < class->vtable_size; ++i) {
2251 if ((cm = class->vtable [i]))
2252 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2254 pvt->vtable [i] = NULL;
2257 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2258 /* create trampolines for abstract methods */
2259 for (k = class; k; k = k->parent) {
2261 gpointer iter = NULL;
2262 while ((m = mono_class_get_methods (k, &iter)))
2263 if (!pvt->vtable [m->slot])
2264 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2268 pvt->max_interface_id = max_interface_id;
2269 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2270 #ifdef COMPRESSED_INTERFACE_BITMAP
2271 bitmap = g_malloc0 (bsize);
2273 bitmap = mono_domain_alloc0 (domain, bsize);
2276 if (! ARCH_USE_IMT) {
2277 /* initialize interface offsets */
2278 for (i = 0; i < class->interface_offsets_count; ++i) {
2279 int interface_id = class->interfaces_packed [i]->interface_id;
2280 int slot = class->interface_offsets_packed [i];
2281 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2284 for (i = 0; i < class->interface_offsets_count; ++i) {
2285 int interface_id = class->interfaces_packed [i]->interface_id;
2286 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2289 if (extra_interfaces) {
2290 int slot = class->vtable_size;
2296 /* Create trampolines for the methods of the interfaces */
2297 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2298 interf = list_item->data;
2300 if (! ARCH_USE_IMT) {
2301 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2303 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2307 while ((cm = mono_class_get_methods (interf, &iter)))
2308 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2310 slot += mono_class_num_methods (interf);
2312 if (! ARCH_USE_IMT) {
2313 g_slist_free (extra_interfaces);
2318 /* Now that the vtable is full, we can actually fill up the IMT */
2319 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2320 if (extra_interfaces) {
2321 g_slist_free (extra_interfaces);
2325 #ifdef COMPRESSED_INTERFACE_BITMAP
2326 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2327 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2328 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2331 pvt->interface_bitmap = bitmap;
2337 * mono_class_field_is_special_static:
2339 * Returns whether @field is a thread/context static field.
2342 mono_class_field_is_special_static (MonoClassField *field)
2344 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2346 if (mono_field_is_deleted (field))
2348 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2349 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2356 * mono_class_field_get_special_static_type:
2357 * @field: The MonoClassField describing the field.
2359 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2360 * SPECIAL_STATIC_NONE otherwise.
2363 mono_class_field_get_special_static_type (MonoClassField *field)
2365 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2366 return SPECIAL_STATIC_NONE;
2367 if (mono_field_is_deleted (field))
2368 return SPECIAL_STATIC_NONE;
2369 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2370 return field_is_special_static (field->parent, field);
2371 return SPECIAL_STATIC_NONE;
2375 * mono_class_has_special_static_fields:
2377 * Returns whenever @klass has any thread/context static fields.
2380 mono_class_has_special_static_fields (MonoClass *klass)
2382 MonoClassField *field;
2386 while ((field = mono_class_get_fields (klass, &iter))) {
2387 g_assert (field->parent == klass);
2388 if (mono_class_field_is_special_static (field))
2396 * create_remote_class_key:
2397 * Creates an array of pointers that can be used as a hash key for a remote class.
2398 * The first element of the array is the number of pointers.
2401 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2406 if (remote_class == NULL) {
2407 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2408 key = g_malloc (sizeof(gpointer) * 3);
2409 key [0] = GINT_TO_POINTER (2);
2410 key [1] = mono_defaults.marshalbyrefobject_class;
2411 key [2] = extra_class;
2413 key = g_malloc (sizeof(gpointer) * 2);
2414 key [0] = GINT_TO_POINTER (1);
2415 key [1] = extra_class;
2418 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2419 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2420 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2421 key [1] = remote_class->proxy_class;
2423 // Keep the list of interfaces sorted
2424 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2425 if (extra_class && remote_class->interfaces [i] > extra_class) {
2426 key [j++] = extra_class;
2429 key [j] = remote_class->interfaces [i];
2432 key [j] = extra_class;
2434 // Replace the old class. The interface list is the same
2435 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2436 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2437 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2438 for (i = 0; i < remote_class->interface_count; i++)
2439 key [2 + i] = remote_class->interfaces [i];
2447 * copy_remote_class_key:
2449 * Make a copy of KEY in the domain and return the copy.
2452 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2454 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2455 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2457 memcpy (mp_key, key, key_size);
2463 * mono_remote_class:
2464 * @domain: the application domain
2465 * @class_name: name of the remote class
2467 * Creates and initializes a MonoRemoteClass object for a remote type.
2469 * Can raise an exception on failure.
2472 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2475 MonoRemoteClass *rc;
2476 gpointer* key, *mp_key;
2479 key = create_remote_class_key (NULL, proxy_class);
2481 mono_domain_lock (domain);
2482 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2486 mono_domain_unlock (domain);
2490 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2491 if (!mono_error_ok (&error)) {
2493 mono_domain_unlock (domain);
2494 mono_error_raise_exception (&error);
2497 mp_key = copy_remote_class_key (domain, key);
2501 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2502 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2503 rc->interface_count = 1;
2504 rc->interfaces [0] = proxy_class;
2505 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2507 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2508 rc->interface_count = 0;
2509 rc->proxy_class = proxy_class;
2512 rc->default_vtable = NULL;
2513 rc->xdomain_vtable = NULL;
2514 rc->proxy_class_name = name;
2515 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2517 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2519 mono_domain_unlock (domain);
2524 * clone_remote_class:
2525 * Creates a copy of the remote_class, adding the provided class or interface
2527 static MonoRemoteClass*
2528 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2530 MonoRemoteClass *rc;
2531 gpointer* key, *mp_key;
2533 key = create_remote_class_key (remote_class, extra_class);
2534 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2540 mp_key = copy_remote_class_key (domain, key);
2544 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2546 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2547 rc->proxy_class = remote_class->proxy_class;
2548 rc->interface_count = remote_class->interface_count + 1;
2550 // Keep the list of interfaces sorted, since the hash key of
2551 // the remote class depends on this
2552 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2553 if (remote_class->interfaces [i] > extra_class && i == j)
2554 rc->interfaces [j++] = extra_class;
2555 rc->interfaces [j] = remote_class->interfaces [i];
2558 rc->interfaces [j] = extra_class;
2560 // Replace the old class. The interface array is the same
2561 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2562 rc->proxy_class = extra_class;
2563 rc->interface_count = remote_class->interface_count;
2564 if (rc->interface_count > 0)
2565 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2568 rc->default_vtable = NULL;
2569 rc->xdomain_vtable = NULL;
2570 rc->proxy_class_name = remote_class->proxy_class_name;
2572 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2578 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2580 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2581 mono_domain_lock (domain);
2582 if (rp->target_domain_id != -1) {
2583 if (remote_class->xdomain_vtable == NULL)
2584 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2585 mono_domain_unlock (domain);
2586 mono_loader_unlock ();
2587 return remote_class->xdomain_vtable;
2589 if (remote_class->default_vtable == NULL) {
2592 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2593 klass = mono_class_from_mono_type (type);
2594 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2595 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2597 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2600 mono_domain_unlock (domain);
2601 mono_loader_unlock ();
2602 return remote_class->default_vtable;
2606 * mono_upgrade_remote_class:
2607 * @domain: the application domain
2608 * @tproxy: the proxy whose remote class has to be upgraded.
2609 * @klass: class to which the remote class can be casted.
2611 * Updates the vtable of the remote class by adding the necessary method slots
2612 * and interface offsets so it can be safely casted to klass. klass can be a
2613 * class or an interface.
2616 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2618 MonoTransparentProxy *tproxy;
2619 MonoRemoteClass *remote_class;
2620 gboolean redo_vtable;
2622 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2623 mono_domain_lock (domain);
2625 tproxy = (MonoTransparentProxy*) proxy_object;
2626 remote_class = tproxy->remote_class;
2628 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2631 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2632 if (remote_class->interfaces [i] == klass)
2633 redo_vtable = FALSE;
2636 redo_vtable = (remote_class->proxy_class != klass);
2640 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2641 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2644 mono_domain_unlock (domain);
2645 mono_loader_unlock ();
2650 * mono_object_get_virtual_method:
2651 * @obj: object to operate on.
2654 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2655 * the instance of a callvirt of method.
2658 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2661 MonoMethod **vtable;
2663 MonoMethod *res = NULL;
2665 klass = mono_object_class (obj);
2666 if (klass == mono_defaults.transparent_proxy_class) {
2667 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2673 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2676 mono_class_setup_vtable (klass);
2677 vtable = klass->vtable;
2679 if (method->slot == -1) {
2680 /* method->slot might not be set for instances of generic methods */
2681 if (method->is_inflated) {
2682 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2683 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2686 g_assert_not_reached ();
2690 /* check method->slot is a valid index: perform isinstance? */
2691 if (method->slot != -1) {
2692 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2694 gboolean variance_used = FALSE;
2695 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2696 g_assert (iface_offset > 0);
2697 res = vtable [iface_offset + method->slot];
2700 res = vtable [method->slot];
2705 /* It may be an interface, abstract class method or generic method */
2706 if (!res || mono_method_signature (res)->generic_param_count)
2709 /* generic methods demand invoke_with_check */
2710 if (mono_method_signature (res)->generic_param_count)
2711 res = mono_marshal_get_remoting_invoke_with_check (res);
2714 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2715 res = mono_cominterop_get_invoke (res);
2718 res = mono_marshal_get_remoting_invoke (res);
2721 if (method->is_inflated) {
2722 /* Have to inflate the result */
2723 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2733 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2735 g_error ("runtime invoke called on uninitialized runtime");
2739 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2742 * mono_runtime_invoke:
2743 * @method: method to invoke
2744 * @obJ: object instance
2745 * @params: arguments to the method
2746 * @exc: exception information.
2748 * Invokes the method represented by @method on the object @obj.
2750 * obj is the 'this' pointer, it should be NULL for static
2751 * methods, a MonoObject* for object instances and a pointer to
2752 * the value type for value types.
2754 * The params array contains the arguments to the method with the
2755 * same convention: MonoObject* pointers for object instances and
2756 * pointers to the value type otherwise.
2758 * From unmanaged code you'll usually use the
2759 * mono_runtime_invoke() variant.
2761 * Note that this function doesn't handle virtual methods for
2762 * you, it will exec the exact method you pass: we still need to
2763 * expose a function to lookup the derived class implementation
2764 * of a virtual method (there are examples of this in the code,
2767 * You can pass NULL as the exc argument if you don't want to
2768 * catch exceptions, otherwise, *exc will be set to the exception
2769 * thrown, if any. if an exception is thrown, you can't use the
2770 * MonoObject* result from the function.
2772 * If the method returns a value type, it is boxed in an object
2776 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2780 if (mono_runtime_get_no_exec ())
2781 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2783 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2784 mono_profiler_method_start_invoke (method);
2786 result = default_mono_runtime_invoke (method, obj, params, exc);
2788 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2789 mono_profiler_method_end_invoke (method);
2795 * mono_method_get_unmanaged_thunk:
2796 * @method: method to generate a thunk for.
2798 * Returns an unmanaged->managed thunk that can be used to call
2799 * a managed method directly from C.
2801 * The thunk's C signature closely matches the managed signature:
2803 * C#: public bool Equals (object obj);
2804 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2805 * MonoObject*, MonoException**);
2807 * The 1st ("this") parameter must not be used with static methods:
2809 * C#: public static bool ReferenceEquals (object a, object b);
2810 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2813 * The last argument must be a non-null pointer of a MonoException* pointer.
2814 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2815 * exception has been thrown in managed code. Otherwise it will point
2816 * to the MonoException* caught by the thunk. In this case, the result of
2817 * the thunk is undefined:
2819 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2820 * MonoException *ex = NULL;
2821 * Equals func = mono_method_get_unmanaged_thunk (method);
2822 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2824 * // handle exception
2827 * The calling convention of the thunk matches the platform's default
2828 * convention. This means that under Windows, C declarations must
2829 * contain the __stdcall attribute:
2831 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2832 * MonoObject*, MonoException**);
2836 * Value type arguments and return values are treated as they were objects:
2838 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2839 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2841 * Arguments must be properly boxed upon trunk's invocation, while return
2842 * values must be unboxed.
2845 mono_method_get_unmanaged_thunk (MonoMethod *method)
2847 method = mono_marshal_get_thunk_invoke_wrapper (method);
2848 return mono_compile_method (method);
2852 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2856 /* object fields cannot be byref, so we don't need a
2858 gpointer *p = (gpointer*)dest;
2865 case MONO_TYPE_BOOLEAN:
2867 case MONO_TYPE_U1: {
2868 guint8 *p = (guint8*)dest;
2869 *p = value ? *(guint8*)value : 0;
2874 case MONO_TYPE_CHAR: {
2875 guint16 *p = (guint16*)dest;
2876 *p = value ? *(guint16*)value : 0;
2879 #if SIZEOF_VOID_P == 4
2884 case MONO_TYPE_U4: {
2885 gint32 *p = (gint32*)dest;
2886 *p = value ? *(gint32*)value : 0;
2889 #if SIZEOF_VOID_P == 8
2894 case MONO_TYPE_U8: {
2895 gint64 *p = (gint64*)dest;
2896 *p = value ? *(gint64*)value : 0;
2899 case MONO_TYPE_R4: {
2900 float *p = (float*)dest;
2901 *p = value ? *(float*)value : 0;
2904 case MONO_TYPE_R8: {
2905 double *p = (double*)dest;
2906 *p = value ? *(double*)value : 0;
2909 case MONO_TYPE_STRING:
2910 case MONO_TYPE_SZARRAY:
2911 case MONO_TYPE_CLASS:
2912 case MONO_TYPE_OBJECT:
2913 case MONO_TYPE_ARRAY:
2914 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2916 case MONO_TYPE_FNPTR:
2917 case MONO_TYPE_PTR: {
2918 gpointer *p = (gpointer*)dest;
2919 *p = deref_pointer? *(gpointer*)value: value;
2922 case MONO_TYPE_VALUETYPE:
2923 /* note that 't' and 'type->type' can be different */
2924 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2925 t = mono_class_enum_basetype (type->data.klass)->type;
2928 MonoClass *class = mono_class_from_mono_type (type);
2929 int size = mono_class_value_size (class, NULL);
2931 mono_gc_bzero (dest, size);
2933 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2936 case MONO_TYPE_GENERICINST:
2937 t = type->data.generic_class->container_class->byval_arg.type;
2940 g_warning ("got type %x", type->type);
2941 g_assert_not_reached ();
2946 * mono_field_set_value:
2947 * @obj: Instance object
2948 * @field: MonoClassField describing the field to set
2949 * @value: The value to be set
2951 * Sets the value of the field described by @field in the object instance @obj
2952 * to the value passed in @value. This method should only be used for instance
2953 * fields. For static fields, use mono_field_static_set_value.
2955 * The value must be on the native format of the field type.
2958 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2962 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2964 dest = (char*)obj + field->offset;
2965 set_value (field->type, dest, value, FALSE);
2969 * mono_field_static_set_value:
2970 * @field: MonoClassField describing the field to set
2971 * @value: The value to be set
2973 * Sets the value of the static field described by @field
2974 * to the value passed in @value.
2976 * The value must be on the native format of the field type.
2979 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2983 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2984 /* you cant set a constant! */
2985 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2987 if (field->offset == -1) {
2988 /* Special static */
2991 mono_domain_lock (vt->domain);
2992 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2993 mono_domain_unlock (vt->domain);
2994 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2996 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2998 set_value (field->type, dest, value, FALSE);
3002 * mono_vtable_get_static_field_data:
3004 * Internal use function: return a pointer to the memory holding the static fields
3005 * for a class or NULL if there are no static fields.
3006 * This is exported only for use by the debugger.
3009 mono_vtable_get_static_field_data (MonoVTable *vt)
3011 if (!vt->has_static_fields)
3013 return vt->vtable [vt->klass->vtable_size];
3017 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3021 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3022 if (field->offset == -1) {
3023 /* Special static */
3026 mono_domain_lock (vt->domain);
3027 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3028 mono_domain_unlock (vt->domain);
3029 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3031 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3034 src = (guint8*)obj + field->offset;
3041 * mono_field_get_value:
3042 * @obj: Object instance
3043 * @field: MonoClassField describing the field to fetch information from
3044 * @value: pointer to the location where the value will be stored
3046 * Use this routine to get the value of the field @field in the object
3049 * The pointer provided by value must be of the field type, for reference
3050 * types this is a MonoObject*, for value types its the actual pointer to
3055 * mono_field_get_value (obj, int_field, &i);
3058 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3064 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3066 src = (char*)obj + field->offset;
3067 set_value (field->type, value, src, TRUE);
3071 * mono_field_get_value_object:
3072 * @domain: domain where the object will be created (if boxing)
3073 * @field: MonoClassField describing the field to fetch information from
3074 * @obj: The object instance for the field.
3076 * Returns: a new MonoObject with the value from the given field. If the
3077 * field represents a value type, the value is boxed.
3081 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3085 MonoVTable *vtable = NULL;
3087 gboolean is_static = FALSE;
3088 gboolean is_ref = FALSE;
3089 gboolean is_literal = FALSE;
3090 gboolean is_ptr = FALSE;
3092 MonoType *type = mono_field_get_type_checked (field, &error);
3094 if (!mono_error_ok (&error))
3095 mono_error_raise_exception (&error);
3097 switch (type->type) {
3098 case MONO_TYPE_STRING:
3099 case MONO_TYPE_OBJECT:
3100 case MONO_TYPE_CLASS:
3101 case MONO_TYPE_ARRAY:
3102 case MONO_TYPE_SZARRAY:
3107 case MONO_TYPE_BOOLEAN:
3110 case MONO_TYPE_CHAR:
3119 case MONO_TYPE_VALUETYPE:
3120 is_ref = type->byref;
3122 case MONO_TYPE_GENERICINST:
3123 is_ref = !mono_type_generic_inst_is_valuetype (type);
3129 g_error ("type 0x%x not handled in "
3130 "mono_field_get_value_object", type->type);
3134 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3137 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3141 vtable = mono_class_vtable (domain, field->parent);
3143 char *name = mono_type_get_full_name (field->parent);
3144 /*FIXME extend this to use the MonoError api*/
3145 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3149 if (!vtable->initialized)
3150 mono_runtime_class_init (vtable);
3158 get_default_field_value (domain, field, &o);
3159 } else if (is_static) {
3160 mono_field_static_get_value (vtable, field, &o);
3162 mono_field_get_value (obj, field, &o);
3168 static MonoMethod *m;
3174 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3175 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3181 get_default_field_value (domain, field, v);
3182 } else if (is_static) {
3183 mono_field_static_get_value (vtable, field, v);
3185 mono_field_get_value (obj, field, v);
3188 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3190 args [1] = mono_type_get_object (mono_domain_get (), type);
3192 return mono_runtime_invoke (m, NULL, args, NULL);
3195 /* boxed value type */
3196 klass = mono_class_from_mono_type (type);
3198 if (mono_class_is_nullable (klass))
3199 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3201 o = mono_object_new (domain, klass);
3202 v = ((gchar *) o) + sizeof (MonoObject);
3205 get_default_field_value (domain, field, v);
3206 } else if (is_static) {
3207 mono_field_static_get_value (vtable, field, v);
3209 mono_field_get_value (obj, field, v);
3216 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3219 const char *p = blob;
3220 mono_metadata_decode_blob_size (p, &p);
3223 case MONO_TYPE_BOOLEAN:
3226 *(guint8 *) value = *p;
3228 case MONO_TYPE_CHAR:
3231 *(guint16*) value = read16 (p);
3235 *(guint32*) value = read32 (p);
3239 *(guint64*) value = read64 (p);
3242 readr4 (p, (float*) value);
3245 readr8 (p, (double*) value);
3247 case MONO_TYPE_STRING:
3248 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3250 case MONO_TYPE_CLASS:
3251 *(gpointer*) value = NULL;
3255 g_warning ("type 0x%02x should not be in constant table", type);
3261 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3263 MonoTypeEnum def_type;
3266 data = mono_class_get_field_default_value (field, &def_type);
3267 mono_get_constant_value_from_blob (domain, def_type, data, value);
3271 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3275 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3277 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3278 get_default_field_value (vt->domain, field, value);
3282 if (field->offset == -1) {
3283 /* Special static */
3284 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3285 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3287 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3289 set_value (field->type, value, src, TRUE);
3293 * mono_field_static_get_value:
3294 * @vt: vtable to the object
3295 * @field: MonoClassField describing the field to fetch information from
3296 * @value: where the value is returned
3298 * Use this routine to get the value of the static field @field value.
3300 * The pointer provided by value must be of the field type, for reference
3301 * types this is a MonoObject*, for value types its the actual pointer to
3306 * mono_field_static_get_value (vt, int_field, &i);
3309 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3311 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3315 * mono_property_set_value:
3316 * @prop: MonoProperty to set
3317 * @obj: instance object on which to act
3318 * @params: parameters to pass to the propery
3319 * @exc: optional exception
3321 * Invokes the property's set method with the given arguments on the
3322 * object instance obj (or NULL for static properties).
3324 * You can pass NULL as the exc argument if you don't want to
3325 * catch exceptions, otherwise, *exc will be set to the exception
3326 * thrown, if any. if an exception is thrown, you can't use the
3327 * MonoObject* result from the function.
3330 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3332 default_mono_runtime_invoke (prop->set, obj, params, exc);
3336 * mono_property_get_value:
3337 * @prop: MonoProperty to fetch
3338 * @obj: instance object on which to act
3339 * @params: parameters to pass to the propery
3340 * @exc: optional exception
3342 * Invokes the property's get method with the given arguments on the
3343 * object instance obj (or NULL for static properties).
3345 * You can pass NULL as the exc argument if you don't want to
3346 * catch exceptions, otherwise, *exc will be set to the exception
3347 * thrown, if any. if an exception is thrown, you can't use the
3348 * MonoObject* result from the function.
3350 * Returns: the value from invoking the get method on the property.
3353 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3355 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3359 * mono_nullable_init:
3360 * @buf: The nullable structure to initialize.
3361 * @value: the value to initialize from
3362 * @klass: the type for the object
3364 * Initialize the nullable structure pointed to by @buf from @value which
3365 * should be a boxed value type. The size of @buf should be able to hold
3366 * as much data as the @klass->instance_size (which is the number of bytes
3367 * that will be copies).
3369 * Since Nullables have variable structure, we can not define a C
3370 * structure for them.
3373 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3375 MonoClass *param_class = klass->cast_class;
3377 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3378 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3380 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3382 if (param_class->has_references)
3383 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3385 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3387 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3392 * mono_nullable_box:
3393 * @buf: The buffer representing the data to be boxed
3394 * @klass: the type to box it as.
3396 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3400 mono_nullable_box (guint8 *buf, MonoClass *klass)
3402 MonoClass *param_class = klass->cast_class;
3404 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3405 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3407 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3408 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3409 if (param_class->has_references)
3410 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3412 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3420 * mono_get_delegate_invoke:
3421 * @klass: The delegate class
3423 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3426 mono_get_delegate_invoke (MonoClass *klass)
3430 /* This is called at runtime, so avoid the slower search in metadata */
3431 mono_class_setup_methods (klass);
3432 if (klass->exception_type)
3434 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3439 * mono_runtime_delegate_invoke:
3440 * @delegate: pointer to a delegate object.
3441 * @params: parameters for the delegate.
3442 * @exc: Pointer to the exception result.
3444 * Invokes the delegate method @delegate with the parameters provided.
3446 * You can pass NULL as the exc argument if you don't want to
3447 * catch exceptions, otherwise, *exc will be set to the exception
3448 * thrown, if any. if an exception is thrown, you can't use the
3449 * MonoObject* result from the function.
3452 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3456 im = mono_get_delegate_invoke (delegate->vtable->klass);
3459 return mono_runtime_invoke (im, delegate, params, exc);
3462 static char **main_args = NULL;
3463 static int num_main_args;
3466 * mono_runtime_get_main_args:
3468 * Returns: a MonoArray with the arguments passed to the main program
3471 mono_runtime_get_main_args (void)
3475 MonoDomain *domain = mono_domain_get ();
3480 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3482 for (i = 0; i < num_main_args; ++i)
3483 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3489 free_main_args (void)
3493 for (i = 0; i < num_main_args; ++i)
3494 g_free (main_args [i]);
3499 * mono_runtime_run_main:
3500 * @method: the method to start the application with (usually Main)
3501 * @argc: number of arguments from the command line
3502 * @argv: array of strings from the command line
3503 * @exc: excetption results
3505 * Execute a standard Main() method (argc/argv contains the
3506 * executable name). This method also sets the command line argument value
3507 * needed by System.Environment.
3512 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3516 MonoArray *args = NULL;
3517 MonoDomain *domain = mono_domain_get ();
3518 gchar *utf8_fullpath;
3519 MonoMethodSignature *sig;
3521 g_assert (method != NULL);
3523 mono_thread_set_main (mono_thread_current ());
3525 main_args = g_new0 (char*, argc);
3526 num_main_args = argc;
3528 if (!g_path_is_absolute (argv [0])) {
3529 gchar *basename = g_path_get_basename (argv [0]);
3530 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3534 utf8_fullpath = mono_utf8_from_external (fullpath);
3535 if(utf8_fullpath == NULL) {
3536 /* Printing the arg text will cause glib to
3537 * whinge about "Invalid UTF-8", but at least
3538 * its relevant, and shows the problem text
3541 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3542 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3549 utf8_fullpath = mono_utf8_from_external (argv[0]);
3550 if(utf8_fullpath == NULL) {
3551 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3552 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3557 main_args [0] = utf8_fullpath;
3559 for (i = 1; i < argc; ++i) {
3562 utf8_arg=mono_utf8_from_external (argv[i]);
3563 if(utf8_arg==NULL) {
3564 /* Ditto the comment about Invalid UTF-8 here */
3565 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3566 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3570 main_args [i] = utf8_arg;
3575 sig = mono_method_signature (method);
3577 g_print ("Unable to load Main method.\n");
3581 if (sig->param_count) {
3582 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3583 for (i = 0; i < argc; ++i) {
3584 /* The encodings should all work, given that
3585 * we've checked all these args for the
3588 gchar *str = mono_utf8_from_external (argv [i]);
3589 MonoString *arg = mono_string_new (domain, str);
3590 mono_array_setref (args, i, arg);
3594 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3597 mono_assembly_set_main (method->klass->image->assembly);
3599 return mono_runtime_exec_main (method, args, exc);
3603 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3605 static MonoMethod *serialize_method;
3610 if (!serialize_method) {
3611 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3612 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3615 if (!serialize_method) {
3620 g_assert (!mono_object_class (obj)->marshalbyref);
3624 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3632 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3634 static MonoMethod *deserialize_method;
3639 if (!deserialize_method) {
3640 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3641 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3643 if (!deserialize_method) {
3650 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3658 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3660 static MonoMethod *get_proxy_method;
3662 MonoDomain *domain = mono_domain_get ();
3663 MonoRealProxy *real_proxy;
3664 MonoReflectionType *reflection_type;
3665 MonoTransparentProxy *transparent_proxy;
3667 if (!get_proxy_method)
3668 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3670 g_assert (obj->vtable->klass->marshalbyref);
3672 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3673 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3675 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3676 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3679 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3683 return (MonoObject*) transparent_proxy;
3687 * mono_object_xdomain_representation
3689 * @target_domain: a domain
3690 * @exc: pointer to a MonoObject*
3692 * Creates a representation of obj in the domain target_domain. This
3693 * is either a copy of obj arrived through via serialization and
3694 * deserialization or a proxy, depending on whether the object is
3695 * serializable or marshal by ref. obj must not be in target_domain.
3697 * If the object cannot be represented in target_domain, NULL is
3698 * returned and *exc is set to an appropriate exception.
3701 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3703 MonoObject *deserialized = NULL;
3704 gboolean failure = FALSE;
3708 if (mono_object_class (obj)->marshalbyref) {
3709 deserialized = make_transparent_proxy (obj, &failure, exc);
3711 MonoDomain *domain = mono_domain_get ();
3712 MonoObject *serialized;
3714 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3715 serialized = serialize_object (obj, &failure, exc);
3716 mono_domain_set_internal_with_options (target_domain, FALSE);
3718 deserialized = deserialize_object (serialized, &failure, exc);
3719 if (domain != target_domain)
3720 mono_domain_set_internal_with_options (domain, FALSE);
3723 return deserialized;
3726 /* Used in call_unhandled_exception_delegate */
3728 create_unhandled_exception_eventargs (MonoObject *exc)
3732 MonoMethod *method = NULL;
3733 MonoBoolean is_terminating = TRUE;
3736 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3739 mono_class_init (klass);
3741 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3742 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3746 args [1] = &is_terminating;
3748 obj = mono_object_new (mono_domain_get (), klass);
3749 mono_runtime_invoke (method, obj, args, NULL);
3754 /* Used in mono_unhandled_exception */
3756 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3757 MonoObject *e = NULL;
3759 MonoDomain *current_domain = mono_domain_get ();
3761 if (domain != current_domain)
3762 mono_domain_set_internal_with_options (domain, FALSE);
3764 g_assert (domain == mono_object_domain (domain->domain));
3766 if (mono_object_domain (exc) != domain) {
3767 MonoObject *serialization_exc;
3769 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3771 if (serialization_exc) {
3773 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3776 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3777 "System.Runtime.Serialization", "SerializationException",
3778 "Could not serialize unhandled exception.");
3782 g_assert (mono_object_domain (exc) == domain);
3784 pa [0] = domain->domain;
3785 pa [1] = create_unhandled_exception_eventargs (exc);
3786 mono_runtime_delegate_invoke (delegate, pa, &e);
3788 if (domain != current_domain)
3789 mono_domain_set_internal_with_options (current_domain, FALSE);
3793 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3794 if (!mono_error_ok (&error)) {
3795 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3796 mono_error_cleanup (&error);
3798 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3804 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3807 * mono_runtime_unhandled_exception_policy_set:
3808 * @policy: the new policy
3810 * This is a VM internal routine.
3812 * Sets the runtime policy for handling unhandled exceptions.
3815 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3816 runtime_unhandled_exception_policy = policy;
3820 * mono_runtime_unhandled_exception_policy_get:
3822 * This is a VM internal routine.
3824 * Gets the runtime policy for handling unhandled exceptions.
3826 MonoRuntimeUnhandledExceptionPolicy
3827 mono_runtime_unhandled_exception_policy_get (void) {
3828 return runtime_unhandled_exception_policy;
3832 * mono_unhandled_exception:
3833 * @exc: exception thrown
3835 * This is a VM internal routine.
3837 * We call this function when we detect an unhandled exception
3838 * in the default domain.
3840 * It invokes the * UnhandledException event in AppDomain or prints
3841 * a warning to the console
3844 mono_unhandled_exception (MonoObject *exc)
3846 MonoDomain *current_domain = mono_domain_get ();
3847 MonoDomain *root_domain = mono_get_root_domain ();
3848 MonoClassField *field;
3849 MonoObject *current_appdomain_delegate;
3850 MonoObject *root_appdomain_delegate;
3852 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3853 "UnhandledException");
3856 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3857 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3858 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3859 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3860 if (current_domain != root_domain) {
3861 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3863 current_appdomain_delegate = NULL;
3866 /* set exitcode only if we will abort the process */
3867 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3869 mono_environment_exitcode_set (1);
3870 mono_print_unhandled_exception (exc);
3872 if (root_appdomain_delegate) {
3873 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3875 if (current_appdomain_delegate) {
3876 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3883 * mono_runtime_exec_managed_code:
3884 * @domain: Application domain
3885 * @main_func: function to invoke from the execution thread
3886 * @main_args: parameter to the main_func
3888 * Launch a new thread to execute a function
3890 * main_func is called back from the thread with main_args as the
3891 * parameter. The callback function is expected to start Main()
3892 * eventually. This function then waits for all managed threads to
3894 * It is not necesseray anymore to execute managed code in a subthread,
3895 * so this function should not be used anymore by default: just
3896 * execute the code and then call mono_thread_manage ().
3899 mono_runtime_exec_managed_code (MonoDomain *domain,
3900 MonoMainThreadFunc main_func,
3903 mono_thread_create (domain, main_func, main_args);
3905 mono_thread_manage ();
3909 * Execute a standard Main() method (args doesn't contain the
3913 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3918 MonoCustomAttrInfo* cinfo;
3919 gboolean has_stathread_attribute;
3920 MonoInternalThread* thread = mono_thread_internal_current ();
3926 domain = mono_object_domain (args);
3927 if (!domain->entry_assembly) {
3929 MonoAssembly *assembly;
3931 assembly = method->klass->image->assembly;
3932 domain->entry_assembly = assembly;
3933 /* Domains created from another domain already have application_base and configuration_file set */
3934 if (domain->setup->application_base == NULL) {
3935 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3938 if (domain->setup->configuration_file == NULL) {
3939 str = g_strconcat (assembly->image->name, ".config", NULL);
3940 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3942 mono_set_private_bin_path_from_config (domain);
3946 cinfo = mono_custom_attrs_from_method (method);
3948 static MonoClass *stathread_attribute = NULL;
3949 if (!stathread_attribute)
3950 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3951 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3953 mono_custom_attrs_free (cinfo);
3955 has_stathread_attribute = FALSE;
3957 if (has_stathread_attribute) {
3958 thread->apartment_state = ThreadApartmentState_STA;
3960 thread->apartment_state = ThreadApartmentState_MTA;
3962 mono_thread_init_apartment_state ();
3964 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3966 /* FIXME: check signature of method */
3967 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3969 res = mono_runtime_invoke (method, NULL, pa, exc);
3971 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3975 mono_environment_exitcode_set (rval);
3977 mono_runtime_invoke (method, NULL, pa, exc);
3981 /* If the return type of Main is void, only
3982 * set the exitcode if an exception was thrown
3983 * (we don't want to blow away an
3984 * explicitly-set exit code)
3987 mono_environment_exitcode_set (rval);
3991 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3997 * mono_install_runtime_invoke:
3998 * @func: Function to install
4000 * This is a VM internal routine
4003 mono_install_runtime_invoke (MonoInvokeFunc func)
4005 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4010 * mono_runtime_invoke_array:
4011 * @method: method to invoke
4012 * @obJ: object instance
4013 * @params: arguments to the method
4014 * @exc: exception information.
4016 * Invokes the method represented by @method on the object @obj.
4018 * obj is the 'this' pointer, it should be NULL for static
4019 * methods, a MonoObject* for object instances and a pointer to
4020 * the value type for value types.
4022 * The params array contains the arguments to the method with the
4023 * same convention: MonoObject* pointers for object instances and
4024 * pointers to the value type otherwise. The _invoke_array
4025 * variant takes a C# object[] as the params argument (MonoArray
4026 * *params): in this case the value types are boxed inside the
4027 * respective reference representation.
4029 * From unmanaged code you'll usually use the
4030 * mono_runtime_invoke() variant.
4032 * Note that this function doesn't handle virtual methods for
4033 * you, it will exec the exact method you pass: we still need to
4034 * expose a function to lookup the derived class implementation
4035 * of a virtual method (there are examples of this in the code,
4038 * You can pass NULL as the exc argument if you don't want to
4039 * catch exceptions, otherwise, *exc will be set to the exception
4040 * thrown, if any. if an exception is thrown, you can't use the
4041 * MonoObject* result from the function.
4043 * If the method returns a value type, it is boxed in an object
4047 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4050 MonoMethodSignature *sig = mono_method_signature (method);
4051 gpointer *pa = NULL;
4054 gboolean has_byref_nullables = FALSE;
4056 if (NULL != params) {
4057 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4058 for (i = 0; i < mono_array_length (params); i++) {
4059 MonoType *t = sig->params [i];
4065 case MONO_TYPE_BOOLEAN:
4068 case MONO_TYPE_CHAR:
4077 case MONO_TYPE_VALUETYPE:
4078 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4079 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4080 pa [i] = mono_array_get (params, MonoObject*, i);
4082 has_byref_nullables = TRUE;
4084 /* MS seems to create the objects if a null is passed in */
4085 if (!mono_array_get (params, MonoObject*, i))
4086 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4090 * We can't pass the unboxed vtype byref to the callee, since
4091 * that would mean the callee would be able to modify boxed
4092 * primitive types. So we (and MS) make a copy of the boxed
4093 * object, pass that to the callee, and replace the original
4094 * boxed object in the arg array with the copy.
4096 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4097 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4098 mono_array_setref (params, i, copy);
4101 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4104 case MONO_TYPE_STRING:
4105 case MONO_TYPE_OBJECT:
4106 case MONO_TYPE_CLASS:
4107 case MONO_TYPE_ARRAY:
4108 case MONO_TYPE_SZARRAY:
4110 pa [i] = mono_array_addr (params, MonoObject*, i);
4111 // FIXME: I need to check this code path
4113 pa [i] = mono_array_get (params, MonoObject*, i);
4115 case MONO_TYPE_GENERICINST:
4117 t = &t->data.generic_class->container_class->this_arg;
4119 t = &t->data.generic_class->container_class->byval_arg;
4121 case MONO_TYPE_PTR: {
4124 /* The argument should be an IntPtr */
4125 arg = mono_array_get (params, MonoObject*, i);
4129 g_assert (arg->vtable->klass == mono_defaults.int_class);
4130 pa [i] = ((MonoIntPtr*)arg)->m_value;
4135 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4140 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4143 if (mono_class_is_nullable (method->klass)) {
4144 /* Need to create a boxed vtype instead */
4150 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4154 obj = mono_object_new (mono_domain_get (), method->klass);
4155 g_assert (obj); /*maybe we should raise a TLE instead?*/
4156 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4157 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4159 if (method->klass->valuetype)
4160 o = mono_object_unbox (obj);
4163 } else if (method->klass->valuetype) {
4164 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4167 mono_runtime_invoke (method, o, pa, exc);
4170 if (mono_class_is_nullable (method->klass)) {
4171 MonoObject *nullable;
4173 /* Convert the unboxed vtype into a Nullable structure */
4174 nullable = mono_object_new (mono_domain_get (), method->klass);
4176 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4177 obj = mono_object_unbox (nullable);
4180 /* obj must be already unboxed if needed */
4181 res = mono_runtime_invoke (method, obj, pa, exc);
4183 if (sig->ret->type == MONO_TYPE_PTR) {
4184 MonoClass *pointer_class;
4185 static MonoMethod *box_method;
4187 MonoObject *box_exc;
4190 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4191 * convert it to a Pointer object.
4193 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4195 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4197 g_assert (res->vtable->klass == mono_defaults.int_class);
4198 box_args [0] = ((MonoIntPtr*)res)->m_value;
4199 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4200 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4201 g_assert (!box_exc);
4204 if (has_byref_nullables) {
4206 * The runtime invoke wrapper already converted byref nullables back,
4207 * and stored them in pa, we just need to copy them back to the
4210 for (i = 0; i < mono_array_length (params); i++) {
4211 MonoType *t = sig->params [i];
4213 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4214 mono_array_setref (params, i, pa [i]);
4223 arith_overflow (void)
4225 mono_raise_exception (mono_get_exception_overflow ());
4229 * mono_object_allocate:
4230 * @size: number of bytes to allocate
4232 * This is a very simplistic routine until we have our GC-aware
4235 * Returns: an allocated object of size @size, or NULL on failure.
4237 static inline void *
4238 mono_object_allocate (size_t size, MonoVTable *vtable)
4241 mono_stats.new_object_count++;
4242 ALLOC_OBJECT (o, vtable, size);
4248 * mono_object_allocate_ptrfree:
4249 * @size: number of bytes to allocate
4251 * Note that the memory allocated is not zeroed.
4252 * Returns: an allocated object of size @size, or NULL on failure.
4254 static inline void *
4255 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4258 mono_stats.new_object_count++;
4259 ALLOC_PTRFREE (o, vtable, size);
4263 static inline void *
4264 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4267 ALLOC_TYPED (o, size, vtable);
4268 mono_stats.new_object_count++;
4275 * @klass: the class of the object that we want to create
4277 * Returns: a newly created object whose definition is
4278 * looked up using @klass. This will not invoke any constructors,
4279 * so the consumer of this routine has to invoke any constructors on
4280 * its own to initialize the object.
4282 * It returns NULL on failure.
4285 mono_object_new (MonoDomain *domain, MonoClass *klass)
4289 MONO_ARCH_SAVE_REGS;
4290 vtable = mono_class_vtable (domain, klass);
4293 return mono_object_new_specific (vtable);
4297 * mono_object_new_pinned:
4299 * Same as mono_object_new, but the returned object will be pinned.
4300 * For SGEN, these objects will only be freed at appdomain unload.
4303 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4307 MONO_ARCH_SAVE_REGS;
4308 vtable = mono_class_vtable (domain, klass);
4313 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4315 return mono_object_new_specific (vtable);
4320 * mono_object_new_specific:
4321 * @vtable: the vtable of the object that we want to create
4323 * Returns: A newly created object with class and domain specified
4327 mono_object_new_specific (MonoVTable *vtable)
4331 MONO_ARCH_SAVE_REGS;
4333 /* check for is_com_object for COM Interop */
4334 if (vtable->remote || vtable->klass->is_com_object)
4337 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4340 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4343 mono_class_init (klass);
4345 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4347 vtable->domain->create_proxy_for_type_method = im;
4350 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4352 o = mono_runtime_invoke (im, NULL, pa, NULL);
4353 if (o != NULL) return o;
4356 return mono_object_new_alloc_specific (vtable);
4360 mono_object_new_alloc_specific (MonoVTable *vtable)
4364 if (!vtable->klass->has_references) {
4365 o = mono_object_new_ptrfree (vtable);
4366 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4367 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4369 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4370 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4372 if (G_UNLIKELY (vtable->klass->has_finalize))
4373 mono_object_register_finalizer (o);
4375 if (G_UNLIKELY (profile_allocs))
4376 mono_profiler_allocation (o, vtable->klass);
4381 mono_object_new_fast (MonoVTable *vtable)
4384 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4389 mono_object_new_ptrfree (MonoVTable *vtable)
4392 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4393 #if NEED_TO_ZERO_PTRFREE
4394 /* an inline memset is much faster for the common vcase of small objects
4395 * note we assume the allocated size is a multiple of sizeof (void*).
4397 if (vtable->klass->instance_size < 128) {
4399 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4400 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4406 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4413 mono_object_new_ptrfree_box (MonoVTable *vtable)
4416 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4417 /* the object will be boxed right away, no need to memzero it */
4422 * mono_class_get_allocation_ftn:
4424 * @for_box: the object will be used for boxing
4425 * @pass_size_in_words:
4427 * Return the allocation function appropriate for the given class.
4431 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4433 *pass_size_in_words = FALSE;
4435 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4436 profile_allocs = FALSE;
4438 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4439 return mono_object_new_specific;
4441 if (!vtable->klass->has_references) {
4442 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4444 return mono_object_new_ptrfree_box;
4445 return mono_object_new_ptrfree;
4448 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4450 return mono_object_new_fast;
4453 * FIXME: This is actually slower than mono_object_new_fast, because
4454 * of the overhead of parameter passing.
4457 *pass_size_in_words = TRUE;
4458 #ifdef GC_REDIRECT_TO_LOCAL
4459 return GC_local_gcj_fast_malloc;
4461 return GC_gcj_fast_malloc;
4466 return mono_object_new_specific;
4470 * mono_object_new_from_token:
4471 * @image: Context where the type_token is hosted
4472 * @token: a token of the type that we want to create
4474 * Returns: A newly created object whose definition is
4475 * looked up using @token in the @image image
4478 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4482 class = mono_class_get (image, token);
4484 return mono_object_new (domain, class);
4489 * mono_object_clone:
4490 * @obj: the object to clone
4492 * Returns: A newly created object who is a shallow copy of @obj
4495 mono_object_clone (MonoObject *obj)
4498 int size = obj->vtable->klass->instance_size;
4500 if (obj->vtable->klass->rank)
4501 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4503 o = mono_object_allocate (size, obj->vtable);
4505 if (obj->vtable->klass->has_references) {
4506 mono_gc_wbarrier_object_copy (o, obj);
4508 int size = obj->vtable->klass->instance_size;
4509 /* do not copy the sync state */
4510 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4512 if (G_UNLIKELY (profile_allocs))
4513 mono_profiler_allocation (o, obj->vtable->klass);
4515 if (obj->vtable->klass->has_finalize)
4516 mono_object_register_finalizer (o);
4521 * mono_array_full_copy:
4522 * @src: source array to copy
4523 * @dest: destination array
4525 * Copies the content of one array to another with exactly the same type and size.
4528 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4531 MonoClass *klass = src->obj.vtable->klass;
4533 MONO_ARCH_SAVE_REGS;
4535 g_assert (klass == dest->obj.vtable->klass);
4537 size = mono_array_length (src);
4538 g_assert (size == mono_array_length (dest));
4539 size *= mono_array_element_size (klass);
4541 if (klass->element_class->valuetype) {
4542 if (klass->element_class->has_references)
4543 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4545 mono_gc_memmove (&dest->vector, &src->vector, size);
4547 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4550 mono_gc_memmove (&dest->vector, &src->vector, size);
4555 * mono_array_clone_in_domain:
4556 * @domain: the domain in which the array will be cloned into
4557 * @array: the array to clone
4559 * This routine returns a copy of the array that is hosted on the
4560 * specified MonoDomain.
4563 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4568 MonoClass *klass = array->obj.vtable->klass;
4570 MONO_ARCH_SAVE_REGS;
4572 if (array->bounds == NULL) {
4573 size = mono_array_length (array);
4574 o = mono_array_new_full (domain, klass, &size, NULL);
4576 size *= mono_array_element_size (klass);
4578 if (klass->element_class->valuetype) {
4579 if (klass->element_class->has_references)
4580 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4582 mono_gc_memmove (&o->vector, &array->vector, size);
4584 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4587 mono_gc_memmove (&o->vector, &array->vector, size);
4592 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4593 size = mono_array_element_size (klass);
4594 for (i = 0; i < klass->rank; ++i) {
4595 sizes [i] = array->bounds [i].length;
4596 size *= array->bounds [i].length;
4597 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4599 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4601 if (klass->element_class->valuetype) {
4602 if (klass->element_class->has_references)
4603 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4605 mono_gc_memmove (&o->vector, &array->vector, size);
4607 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4610 mono_gc_memmove (&o->vector, &array->vector, size);
4618 * @array: the array to clone
4620 * Returns: A newly created array who is a shallow copy of @array
4623 mono_array_clone (MonoArray *array)
4625 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4628 /* helper macros to check for overflow when calculating the size of arrays */
4629 #ifdef MONO_BIG_ARRAYS
4630 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4631 #define MYGUINT_MAX MYGUINT64_MAX
4632 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4633 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4634 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4635 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4636 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4638 #define MYGUINT32_MAX 4294967295U
4639 #define MYGUINT_MAX MYGUINT32_MAX
4640 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4641 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4642 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4643 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4644 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4648 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4652 byte_len = mono_array_element_size (class);
4653 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4656 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4658 byte_len += sizeof (MonoArray);
4666 * mono_array_new_full:
4667 * @domain: domain where the object is created
4668 * @array_class: array class
4669 * @lengths: lengths for each dimension in the array
4670 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4672 * This routine creates a new array objects with the given dimensions,
4673 * lower bounds and type.
4676 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4678 uintptr_t byte_len, len, bounds_size;
4681 MonoArrayBounds *bounds;
4685 if (!array_class->inited)
4686 mono_class_init (array_class);
4690 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4691 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4693 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4697 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4699 for (i = 0; i < array_class->rank; ++i) {
4700 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4702 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4703 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4708 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4709 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4713 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4714 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4715 byte_len = (byte_len + 3) & ~3;
4716 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4717 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4718 byte_len += bounds_size;
4721 * Following three lines almost taken from mono_object_new ():
4722 * they need to be kept in sync.
4724 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4725 #ifndef HAVE_SGEN_GC
4726 if (!array_class->has_references) {
4727 o = mono_object_allocate_ptrfree (byte_len, vtable);
4728 #if NEED_TO_ZERO_PTRFREE
4729 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4731 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4732 o = mono_object_allocate_spec (byte_len, vtable);
4734 o = mono_object_allocate (byte_len, vtable);
4737 array = (MonoArray*)o;
4738 array->max_length = len;
4741 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4742 array->bounds = bounds;
4746 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4748 o = mono_gc_alloc_vector (vtable, byte_len, len);
4749 array = (MonoArray*)o;
4750 mono_stats.new_object_count++;
4752 bounds = array->bounds;
4756 for (i = 0; i < array_class->rank; ++i) {
4757 bounds [i].length = lengths [i];
4759 bounds [i].lower_bound = lower_bounds [i];
4763 if (G_UNLIKELY (profile_allocs))
4764 mono_profiler_allocation (o, array_class);
4771 * @domain: domain where the object is created
4772 * @eclass: element class
4773 * @n: number of array elements
4775 * This routine creates a new szarray with @n elements of type @eclass.
4778 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4782 MONO_ARCH_SAVE_REGS;
4784 ac = mono_array_class_get (eclass, 1);
4787 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4791 * mono_array_new_specific:
4792 * @vtable: a vtable in the appropriate domain for an initialized class
4793 * @n: number of array elements
4795 * This routine is a fast alternative to mono_array_new() for code which
4796 * can be sure about the domain it operates in.
4799 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4805 MONO_ARCH_SAVE_REGS;
4807 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4812 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4813 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4816 #ifndef HAVE_SGEN_GC
4817 if (!vtable->klass->has_references) {
4818 o = mono_object_allocate_ptrfree (byte_len, vtable);
4819 #if NEED_TO_ZERO_PTRFREE
4820 ((MonoArray*)o)->bounds = NULL;
4821 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4823 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4824 o = mono_object_allocate_spec (byte_len, vtable);
4826 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4827 o = mono_object_allocate (byte_len, vtable);
4830 ao = (MonoArray *)o;
4833 o = mono_gc_alloc_vector (vtable, byte_len, n);
4835 mono_stats.new_object_count++;
4838 if (G_UNLIKELY (profile_allocs))
4839 mono_profiler_allocation (o, vtable->klass);
4845 * mono_string_new_utf16:
4846 * @text: a pointer to an utf16 string
4847 * @len: the length of the string
4849 * Returns: A newly created string object which contains @text.
4852 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4856 s = mono_string_new_size (domain, len);
4857 g_assert (s != NULL);
4859 memcpy (mono_string_chars (s), text, len * 2);
4865 * mono_string_new_size:
4866 * @text: a pointer to an utf16 string
4867 * @len: the length of the string
4869 * Returns: A newly created string object of @len
4872 mono_string_new_size (MonoDomain *domain, gint32 len)
4876 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4878 /* overflow ? can't fit it, can't allocate it! */
4880 mono_gc_out_of_memory (-1);
4882 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4885 #ifndef HAVE_SGEN_GC
4886 s = mono_object_allocate_ptrfree (size, vtable);
4890 s = mono_gc_alloc_string (vtable, size, len);
4892 #if NEED_TO_ZERO_PTRFREE
4895 if (G_UNLIKELY (profile_allocs))
4896 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4902 * mono_string_new_len:
4903 * @text: a pointer to an utf8 string
4904 * @length: number of bytes in @text to consider
4906 * Returns: A newly created string object which contains @text.
4909 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4911 GError *error = NULL;
4912 MonoString *o = NULL;
4914 glong items_written;
4916 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4919 o = mono_string_new_utf16 (domain, ut, items_written);
4921 g_error_free (error);
4930 * @text: a pointer to an utf8 string
4932 * Returns: A newly created string object which contains @text.
4935 mono_string_new (MonoDomain *domain, const char *text)
4937 GError *error = NULL;
4938 MonoString *o = NULL;
4940 glong items_written;
4945 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4948 o = mono_string_new_utf16 (domain, ut, items_written);
4950 g_error_free (error);
4953 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4958 MonoString *o = NULL;
4960 if (!g_utf8_validate (text, -1, &end))
4963 len = g_utf8_strlen (text, -1);
4964 o = mono_string_new_size (domain, len);
4965 str = mono_string_chars (o);
4967 while (text < end) {
4968 *str++ = g_utf8_get_char (text);
4969 text = g_utf8_next_char (text);
4976 * mono_string_new_wrapper:
4977 * @text: pointer to utf8 characters.
4979 * Helper function to create a string object from @text in the current domain.
4982 mono_string_new_wrapper (const char *text)
4984 MonoDomain *domain = mono_domain_get ();
4986 MONO_ARCH_SAVE_REGS;
4989 return mono_string_new (domain, text);
4996 * @class: the class of the value
4997 * @value: a pointer to the unboxed data
4999 * Returns: A newly created object which contains @value.
5002 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5008 g_assert (class->valuetype);
5009 if (mono_class_is_nullable (class))
5010 return mono_nullable_box (value, class);
5012 vtable = mono_class_vtable (domain, class);
5015 size = mono_class_instance_size (class);
5016 res = mono_object_new_alloc_specific (vtable);
5017 if (G_UNLIKELY (profile_allocs))
5018 mono_profiler_allocation (res, class);
5020 size = size - sizeof (MonoObject);
5023 g_assert (size == mono_class_value_size (class, NULL));
5024 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5026 #if NO_UNALIGNED_ACCESS
5027 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5031 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5034 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5037 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5040 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5043 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5047 if (class->has_finalize)
5048 mono_object_register_finalizer (res);
5054 * @dest: destination pointer
5055 * @src: source pointer
5056 * @klass: a valuetype class
5058 * Copy a valuetype from @src to @dest. This function must be used
5059 * when @klass contains references fields.
5062 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5064 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5068 * mono_value_copy_array:
5069 * @dest: destination array
5070 * @dest_idx: index in the @dest array
5071 * @src: source pointer
5072 * @count: number of items
5074 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5075 * This function must be used when @klass contains references fields.
5076 * Overlap is handled.
5079 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5081 int size = mono_array_element_size (dest->obj.vtable->klass);
5082 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5083 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5084 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5088 * mono_object_get_domain:
5089 * @obj: object to query
5091 * Returns: the MonoDomain where the object is hosted
5094 mono_object_get_domain (MonoObject *obj)
5096 return mono_object_domain (obj);
5100 * mono_object_get_class:
5101 * @obj: object to query
5103 * Returns: the MonOClass of the object.
5106 mono_object_get_class (MonoObject *obj)
5108 return mono_object_class (obj);
5111 * mono_object_get_size:
5112 * @o: object to query
5114 * Returns: the size, in bytes, of @o
5117 mono_object_get_size (MonoObject* o)
5119 MonoClass* klass = mono_object_class (o);
5120 if (klass == mono_defaults.string_class) {
5121 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5122 } else if (o->vtable->rank) {
5123 MonoArray *array = (MonoArray*)o;
5124 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5125 if (array->bounds) {
5128 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5132 return mono_class_instance_size (klass);
5137 * mono_object_unbox:
5138 * @obj: object to unbox
5140 * Returns: a pointer to the start of the valuetype boxed in this
5143 * This method will assert if the object passed is not a valuetype.
5146 mono_object_unbox (MonoObject *obj)
5148 /* add assert for valuetypes? */
5149 g_assert (obj->vtable->klass->valuetype);
5150 return ((char*)obj) + sizeof (MonoObject);
5154 * mono_object_isinst:
5156 * @klass: a pointer to a class
5158 * Returns: @obj if @obj is derived from @klass
5161 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5164 mono_class_init (klass);
5166 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5167 return mono_object_isinst_mbyref (obj, klass);
5172 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5176 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5185 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5186 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5190 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5191 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5194 MonoClass *oklass = vt->klass;
5195 if ((oklass == mono_defaults.transparent_proxy_class))
5196 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5198 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5202 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5204 MonoDomain *domain = mono_domain_get ();
5206 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5207 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5208 MonoMethod *im = NULL;
5211 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5212 im = mono_object_get_virtual_method (rp, im);
5215 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5218 res = mono_runtime_invoke (im, rp, pa, NULL);
5220 if (*(MonoBoolean *) mono_object_unbox(res)) {
5221 /* Update the vtable of the remote type, so it can safely cast to this new type */
5222 mono_upgrade_remote_class (domain, obj, klass);
5231 * mono_object_castclass_mbyref:
5233 * @klass: a pointer to a class
5235 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5238 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5240 if (!obj) return NULL;
5241 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5243 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5245 "InvalidCastException"));
5250 MonoDomain *orig_domain;
5256 str_lookup (MonoDomain *domain, gpointer user_data)
5258 LDStrInfo *info = user_data;
5259 if (info->res || domain == info->orig_domain)
5261 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5267 mono_string_get_pinned (MonoString *str)
5271 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5272 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5274 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5275 news->length = mono_string_length (str);
5281 #define mono_string_get_pinned(str) (str)
5285 mono_string_is_interned_lookup (MonoString *str, int insert)
5287 MonoGHashTable *ldstr_table;
5291 domain = ((MonoObject *)str)->vtable->domain;
5292 ldstr_table = domain->ldstr_table;
5294 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5299 str = mono_string_get_pinned (str);
5301 mono_g_hash_table_insert (ldstr_table, str, str);
5305 LDStrInfo ldstr_info;
5306 ldstr_info.orig_domain = domain;
5307 ldstr_info.ins = str;
5308 ldstr_info.res = NULL;
5310 mono_domain_foreach (str_lookup, &ldstr_info);
5311 if (ldstr_info.res) {
5313 * the string was already interned in some other domain:
5314 * intern it in the current one as well.
5316 mono_g_hash_table_insert (ldstr_table, str, str);
5326 * mono_string_is_interned:
5327 * @o: String to probe
5329 * Returns whether the string has been interned.
5332 mono_string_is_interned (MonoString *o)
5334 return mono_string_is_interned_lookup (o, FALSE);
5338 * mono_string_intern:
5339 * @o: String to intern
5341 * Interns the string passed.
5342 * Returns: The interned string.
5345 mono_string_intern (MonoString *str)
5347 return mono_string_is_interned_lookup (str, TRUE);
5352 * @domain: the domain where the string will be used.
5353 * @image: a metadata context
5354 * @idx: index into the user string table.
5356 * Implementation for the ldstr opcode.
5357 * Returns: a loaded string from the @image/@idx combination.
5360 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5362 MONO_ARCH_SAVE_REGS;
5364 if (image->dynamic) {
5365 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5368 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5369 return NULL; /*FIXME we should probably be raising an exception here*/
5370 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5375 * mono_ldstr_metadata_sig
5376 * @domain: the domain for the string
5377 * @sig: the signature of a metadata string
5379 * Returns: a MonoString for a string stored in the metadata
5382 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5384 const char *str = sig;
5385 MonoString *o, *interned;
5388 len2 = mono_metadata_decode_blob_size (str, &str);
5391 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5392 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5395 guint16 *p2 = (guint16*)mono_string_chars (o);
5396 for (i = 0; i < len2; ++i) {
5397 *p2 = GUINT16_FROM_LE (*p2);
5403 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5405 /* o will get garbage collected */
5409 o = mono_string_get_pinned (o);
5411 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5418 * mono_string_to_utf8:
5419 * @s: a System.String
5421 * Returns the UTF8 representation for @s.
5422 * The resulting buffer needs to be freed with mono_free().
5424 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5427 mono_string_to_utf8 (MonoString *s)
5430 char *result = mono_string_to_utf8_checked (s, &error);
5432 if (!mono_error_ok (&error))
5433 mono_error_raise_exception (&error);
5438 * mono_string_to_utf8_checked:
5439 * @s: a System.String
5440 * @error: a MonoError.
5442 * Converts a MonoString to its UTF8 representation. May fail; check
5443 * @error to determine whether the conversion was successful.
5444 * The resulting buffer should be freed with mono_free().
5447 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5451 GError *gerror = NULL;
5453 mono_error_init (error);
5459 return g_strdup ("");
5461 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5463 mono_error_set_argument (error, "string", "%s", gerror->message);
5464 g_error_free (gerror);
5467 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5468 if (s->length > written) {
5469 /* allocate the total length and copy the part of the string that has been converted */
5470 char *as2 = g_malloc0 (s->length);
5471 memcpy (as2, as, written);
5480 * mono_string_to_utf8_ignore:
5483 * Converts a MonoString to its UTF8 representation. Will ignore
5484 * invalid surrogate pairs.
5485 * The resulting buffer should be freed with mono_free().
5489 mono_string_to_utf8_ignore (MonoString *s)
5498 return g_strdup ("");
5500 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5502 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5503 if (s->length > written) {
5504 /* allocate the total length and copy the part of the string that has been converted */
5505 char *as2 = g_malloc0 (s->length);
5506 memcpy (as2, as, written);
5515 * mono_string_to_utf8_image_ignore:
5516 * @s: a System.String
5518 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5521 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5523 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5527 * mono_string_to_utf8_mp_ignore:
5528 * @s: a System.String
5530 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5533 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5535 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5540 * mono_string_to_utf16:
5543 * Return an null-terminated array of the utf-16 chars
5544 * contained in @s. The result must be freed with g_free().
5545 * This is a temporary helper until our string implementation
5546 * is reworked to always include the null terminating char.
5549 mono_string_to_utf16 (MonoString *s)
5556 as = g_malloc ((s->length * 2) + 2);
5557 as [(s->length * 2)] = '\0';
5558 as [(s->length * 2) + 1] = '\0';
5561 return (gunichar2 *)(as);
5564 memcpy (as, mono_string_chars(s), s->length * 2);
5565 return (gunichar2 *)(as);
5569 * mono_string_from_utf16:
5570 * @data: the UTF16 string (LPWSTR) to convert
5572 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5574 * Returns: a MonoString.
5577 mono_string_from_utf16 (gunichar2 *data)
5579 MonoDomain *domain = mono_domain_get ();
5585 while (data [len]) len++;
5587 return mono_string_new_utf16 (domain, data, len);
5592 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5599 r = mono_string_to_utf8_ignore (s);
5601 r = mono_string_to_utf8_checked (s, error);
5602 if (!mono_error_ok (error))
5609 len = strlen (r) + 1;
5611 mp_s = mono_mempool_alloc (mp, len);
5613 mp_s = mono_image_alloc (image, len);
5615 memcpy (mp_s, r, len);
5623 * mono_string_to_utf8_image:
5624 * @s: a System.String
5626 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5629 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5631 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5635 * mono_string_to_utf8_mp:
5636 * @s: a System.String
5638 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5641 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5643 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5647 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5650 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5652 eh_callbacks = *cbs;
5655 MonoRuntimeExceptionHandlingCallbacks *
5656 mono_get_eh_callbacks (void)
5658 return &eh_callbacks;
5662 * mono_raise_exception:
5663 * @ex: exception object
5665 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5668 mono_raise_exception (MonoException *ex)
5671 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5672 * that will cause gcc to omit the function epilog, causing problems when
5673 * the JIT tries to walk the stack, since the return address on the stack
5674 * will point into the next function in the executable, not this one.
5677 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5678 MonoInternalThread *thread = mono_thread_internal_current ();
5679 g_assert (ex->object.vtable->domain == mono_domain_get ());
5680 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5683 eh_callbacks.mono_raise_exception (ex);
5687 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5689 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5690 MonoInternalThread *thread = mono_thread_internal_current ();
5691 g_assert (ex->object.vtable->domain == mono_domain_get ());
5692 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5695 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5699 * mono_wait_handle_new:
5700 * @domain: Domain where the object will be created
5701 * @handle: Handle for the wait handle
5703 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5706 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5708 MonoWaitHandle *res;
5709 gpointer params [1];
5710 static MonoMethod *handle_set;
5712 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5714 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5716 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5718 params [0] = &handle;
5719 mono_runtime_invoke (handle_set, res, params, NULL);
5725 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5727 static MonoClassField *f_os_handle;
5728 static MonoClassField *f_safe_handle;
5730 if (!f_os_handle && !f_safe_handle) {
5731 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5732 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5737 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5741 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5748 mono_runtime_capture_context (MonoDomain *domain)
5750 RuntimeInvokeFunction runtime_invoke;
5752 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5753 MonoMethod *method = mono_get_context_capture_method ();
5754 MonoMethod *wrapper;
5757 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5758 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5759 domain->capture_context_method = mono_compile_method (method);
5762 runtime_invoke = domain->capture_context_runtime_invoke;
5764 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5767 * mono_async_result_new:
5768 * @domain:domain where the object will be created.
5769 * @handle: wait handle.
5770 * @state: state to pass to AsyncResult
5771 * @data: C closure data.
5773 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5774 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5778 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5780 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5781 MonoObject *context = mono_runtime_capture_context (domain);
5782 /* we must capture the execution context from the original thread */
5784 MONO_OBJECT_SETREF (res, execution_context, context);
5785 /* note: result may be null if the flow is suppressed */
5789 MONO_OBJECT_SETREF (res, object_data, object_data);
5790 MONO_OBJECT_SETREF (res, async_state, state);
5792 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5794 res->sync_completed = FALSE;
5795 res->completed = FALSE;
5801 mono_message_init (MonoDomain *domain,
5802 MonoMethodMessage *this,
5803 MonoReflectionMethod *method,
5804 MonoArray *out_args)
5806 static MonoClass *object_array_klass;
5807 static MonoClass *byte_array_klass;
5808 static MonoClass *string_array_klass;
5809 MonoMethodSignature *sig = mono_method_signature (method->method);
5815 if (!object_array_klass) {
5818 klass = mono_array_class_get (mono_defaults.object_class, 1);
5821 mono_memory_barrier ();
5822 object_array_klass = klass;
5824 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5827 mono_memory_barrier ();
5828 byte_array_klass = klass;
5830 klass = mono_array_class_get (mono_defaults.string_class, 1);
5833 mono_memory_barrier ();
5834 string_array_klass = klass;
5837 MONO_OBJECT_SETREF (this, method, method);
5839 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5840 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5841 this->async_result = NULL;
5842 this->call_type = CallType_Sync;
5844 names = g_new (char *, sig->param_count);
5845 mono_method_get_param_names (method->method, (const char **) names);
5846 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5848 for (i = 0; i < sig->param_count; i++) {
5849 name = mono_string_new (domain, names [i]);
5850 mono_array_setref (this->names, i, name);
5854 for (i = 0, j = 0; i < sig->param_count; i++) {
5855 if (sig->params [i]->byref) {
5857 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5858 mono_array_setref (this->args, i, arg);
5862 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5866 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5869 mono_array_set (this->arg_types, guint8, i, arg_type);
5874 * mono_remoting_invoke:
5875 * @real_proxy: pointer to a RealProxy object
5876 * @msg: The MonoMethodMessage to execute
5877 * @exc: used to store exceptions
5878 * @out_args: used to store output arguments
5880 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5881 * IMessage interface and it is not trivial to extract results from there. So
5882 * we call an helper method PrivateInvoke instead of calling
5883 * RealProxy::Invoke() directly.
5885 * Returns: the result object.
5888 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5889 MonoObject **exc, MonoArray **out_args)
5891 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5894 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5897 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5899 real_proxy->vtable->domain->private_invoke_method = im;
5902 pa [0] = real_proxy;
5907 return mono_runtime_invoke (im, NULL, pa, exc);
5911 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5912 MonoObject **exc, MonoArray **out_args)
5914 static MonoClass *object_array_klass;
5917 MonoMethodSignature *sig;
5919 int i, j, outarg_count = 0;
5921 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5923 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5924 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5925 target = tp->rp->unwrapped_server;
5927 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5931 domain = mono_domain_get ();
5932 method = msg->method->method;
5933 sig = mono_method_signature (method);
5935 for (i = 0; i < sig->param_count; i++) {
5936 if (sig->params [i]->byref)
5940 if (!object_array_klass) {
5943 klass = mono_array_class_get (mono_defaults.object_class, 1);
5946 mono_memory_barrier ();
5947 object_array_klass = klass;
5950 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5951 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5954 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5956 for (i = 0, j = 0; i < sig->param_count; i++) {
5957 if (sig->params [i]->byref) {
5959 arg = mono_array_get (msg->args, gpointer, i);
5960 mono_array_setref (*out_args, j, arg);
5969 * mono_object_to_string:
5971 * @exc: Any exception thrown by ToString (). May be NULL.
5973 * Returns: the result of calling ToString () on an object.
5976 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5978 static MonoMethod *to_string = NULL;
5984 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5986 method = mono_object_get_virtual_method (obj, to_string);
5988 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5992 * mono_print_unhandled_exception:
5993 * @exc: The exception
5995 * Prints the unhandled exception.
5998 mono_print_unhandled_exception (MonoObject *exc)
6001 char *message = (char*)"";
6002 gboolean free_message = FALSE;
6005 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6006 message = g_strdup ("OutOfMemoryException");
6008 str = mono_object_to_string (exc, NULL);
6010 message = mono_string_to_utf8_checked (str, &error);
6011 if (!mono_error_ok (&error)) {
6012 mono_error_cleanup (&error);
6013 message = (char *) "";
6015 free_message = TRUE;
6021 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6022 * exc->vtable->klass->name, message);
6024 g_printerr ("\nUnhandled Exception: %s\n", message);
6031 * mono_delegate_ctor:
6032 * @this: pointer to an uninitialized delegate object
6033 * @target: target object
6034 * @addr: pointer to native code
6037 * Initialize a delegate and sets a specific method, not the one
6038 * associated with addr. This is useful when sharing generic code.
6039 * In that case addr will most probably not be associated with the
6040 * correct instantiation of the method.
6043 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6045 MonoDelegate *delegate = (MonoDelegate *)this;
6052 delegate->method = method;
6054 class = this->vtable->klass;
6055 mono_stats.delegate_creations++;
6057 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6059 method = mono_marshal_get_remoting_invoke (method);
6060 delegate->method_ptr = mono_compile_method (method);
6061 MONO_OBJECT_SETREF (delegate, target, target);
6062 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6063 method = mono_marshal_get_unbox_wrapper (method);
6064 delegate->method_ptr = mono_compile_method (method);
6065 MONO_OBJECT_SETREF (delegate, target, target);
6067 delegate->method_ptr = addr;
6068 MONO_OBJECT_SETREF (delegate, target, target);
6071 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6075 * mono_delegate_ctor:
6076 * @this: pointer to an uninitialized delegate object
6077 * @target: target object
6078 * @addr: pointer to native code
6080 * This is used to initialize a delegate.
6083 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6085 MonoDomain *domain = mono_domain_get ();
6087 MonoMethod *method = NULL;
6091 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6092 method = ji->method;
6093 g_assert (!method->klass->generic_container);
6096 mono_delegate_ctor_with_method (this, target, addr, method);
6100 * mono_method_call_message_new:
6101 * @method: method to encapsulate
6102 * @params: parameters to the method
6103 * @invoke: optional, delegate invoke.
6104 * @cb: async callback delegate.
6105 * @state: state passed to the async callback.
6107 * Translates arguments pointers into a MonoMethodMessage.
6110 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6111 MonoDelegate **cb, MonoObject **state)
6113 MonoDomain *domain = mono_domain_get ();
6114 MonoMethodSignature *sig = mono_method_signature (method);
6115 MonoMethodMessage *msg;
6118 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6121 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6122 count = sig->param_count - 2;
6124 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6125 count = sig->param_count;
6128 for (i = 0; i < count; i++) {
6133 if (sig->params [i]->byref)
6134 vpos = *((gpointer *)params [i]);
6138 type = sig->params [i]->type;
6139 class = mono_class_from_mono_type (sig->params [i]);
6141 if (class->valuetype)
6142 arg = mono_value_box (domain, class, vpos);
6144 arg = *((MonoObject **)vpos);
6146 mono_array_setref (msg->args, i, arg);
6149 if (cb != NULL && state != NULL) {
6150 *cb = *((MonoDelegate **)params [i]);
6152 *state = *((MonoObject **)params [i]);
6159 * mono_method_return_message_restore:
6161 * Restore results from message based processing back to arguments pointers
6164 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6166 MonoMethodSignature *sig = mono_method_signature (method);
6167 int i, j, type, size, out_len;
6169 if (out_args == NULL)
6171 out_len = mono_array_length (out_args);
6175 for (i = 0, j = 0; i < sig->param_count; i++) {
6176 MonoType *pt = sig->params [i];
6181 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6183 arg = mono_array_get (out_args, gpointer, j);
6186 g_assert (type != MONO_TYPE_VOID);
6188 if (MONO_TYPE_IS_REFERENCE (pt)) {
6189 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6192 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6193 size = mono_class_value_size (class, NULL);
6194 if (class->has_references)
6195 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6197 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6199 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6200 mono_gc_bzero (*((gpointer *)params [i]), size);
6210 * mono_load_remote_field:
6211 * @this: pointer to an object
6212 * @klass: klass of the object containing @field
6213 * @field: the field to load
6214 * @res: a storage to store the result
6216 * This method is called by the runtime on attempts to load fields of
6217 * transparent proxy objects. @this points to such TP, @klass is the class of
6218 * the object containing @field. @res is a storage location which can be
6219 * used to store the result.
6221 * Returns: an address pointing to the value of field.
6224 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6226 static MonoMethod *getter = NULL;
6227 MonoDomain *domain = mono_domain_get ();
6228 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6229 MonoClass *field_class;
6230 MonoMethodMessage *msg;
6231 MonoArray *out_args;
6235 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6236 g_assert (res != NULL);
6238 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6239 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6244 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6248 field_class = mono_class_from_mono_type (field->type);
6250 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6251 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6252 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6254 full_name = mono_type_get_full_name (klass);
6255 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6256 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6259 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6261 if (exc) mono_raise_exception ((MonoException *)exc);
6263 if (mono_array_length (out_args) == 0)
6266 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6268 if (field_class->valuetype) {
6269 return ((char *)*res) + sizeof (MonoObject);
6275 * mono_load_remote_field_new:
6280 * Missing documentation.
6283 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6285 static MonoMethod *getter = NULL;
6286 MonoDomain *domain = mono_domain_get ();
6287 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6288 MonoClass *field_class;
6289 MonoMethodMessage *msg;
6290 MonoArray *out_args;
6291 MonoObject *exc, *res;
6294 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6296 field_class = mono_class_from_mono_type (field->type);
6298 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6300 if (field_class->valuetype) {
6301 res = mono_object_new (domain, field_class);
6302 val = ((gchar *) res) + sizeof (MonoObject);
6306 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6311 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6315 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6316 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6318 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6320 full_name = mono_type_get_full_name (klass);
6321 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6322 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6325 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6327 if (exc) mono_raise_exception ((MonoException *)exc);
6329 if (mono_array_length (out_args) == 0)
6332 res = mono_array_get (out_args, MonoObject *, 0);
6338 * mono_store_remote_field:
6339 * @this: pointer to an object
6340 * @klass: klass of the object containing @field
6341 * @field: the field to load
6342 * @val: the value/object to store
6344 * This method is called by the runtime on attempts to store fields of
6345 * transparent proxy objects. @this points to such TP, @klass is the class of
6346 * the object containing @field. @val is the new value to store in @field.
6349 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6351 static MonoMethod *setter = NULL;
6352 MonoDomain *domain = mono_domain_get ();
6353 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6354 MonoClass *field_class;
6355 MonoMethodMessage *msg;
6356 MonoArray *out_args;
6361 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6363 field_class = mono_class_from_mono_type (field->type);
6365 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6366 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6367 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6372 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6376 if (field_class->valuetype)
6377 arg = mono_value_box (domain, field_class, val);
6379 arg = *((MonoObject **)val);
6382 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6383 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6385 full_name = mono_type_get_full_name (klass);
6386 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6387 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6388 mono_array_setref (msg->args, 2, arg);
6391 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6393 if (exc) mono_raise_exception ((MonoException *)exc);
6397 * mono_store_remote_field_new:
6403 * Missing documentation
6406 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6408 static MonoMethod *setter = NULL;
6409 MonoDomain *domain = mono_domain_get ();
6410 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6411 MonoClass *field_class;
6412 MonoMethodMessage *msg;
6413 MonoArray *out_args;
6417 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6419 field_class = mono_class_from_mono_type (field->type);
6421 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6422 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6423 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6428 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6432 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6433 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6435 full_name = mono_type_get_full_name (klass);
6436 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6437 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6438 mono_array_setref (msg->args, 2, arg);
6441 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6443 if (exc) mono_raise_exception ((MonoException *)exc);
6447 * mono_create_ftnptr:
6449 * Given a function address, create a function descriptor for it.
6450 * This is only needed on some platforms.
6453 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6455 return callbacks.create_ftnptr (domain, addr);
6459 * mono_get_addr_from_ftnptr:
6461 * Given a pointer to a function descriptor, return the function address.
6462 * This is only needed on some platforms.
6465 mono_get_addr_from_ftnptr (gpointer descr)
6467 return callbacks.get_addr_from_ftnptr (descr);
6471 * mono_string_chars:
6474 * Returns a pointer to the UCS16 characters stored in the MonoString
6477 mono_string_chars (MonoString *s)
6483 * mono_string_length:
6486 * Returns the lenght in characters of the string
6489 mono_string_length (MonoString *s)
6495 * mono_array_length:
6496 * @array: a MonoArray*
6498 * Returns the total number of elements in the array. This works for
6499 * both vectors and multidimensional arrays.
6502 mono_array_length (MonoArray *array)
6504 return array->max_length;
6508 * mono_array_addr_with_size:
6509 * @array: a MonoArray*
6510 * @size: size of the array elements
6511 * @idx: index into the array
6513 * Returns the address of the @idx element in the array.
6516 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6518 return ((char*)(array)->vector) + size * idx;