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);
104 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
106 if (method->klass->valuetype)
107 this = mono_object_unbox (this);
108 mono_runtime_invoke (method, this, NULL, NULL);
111 /* The pseudo algorithm for type initialization from the spec
112 Note it doesn't say anything about domains - only threads.
114 2. If the type is initialized you are done.
115 2.1. If the type is not yet initialized, try to take an
117 2.2. If successful, record this thread as responsible for
118 initializing the type and proceed to step 2.3.
119 2.2.1. If not, see whether this thread or any thread
120 waiting for this thread to complete already holds the lock.
121 2.2.2. If so, return since blocking would create a deadlock. This thread
122 will now see an incompletely initialized state for the type,
123 but no deadlock will arise.
124 2.2.3 If not, block until the type is initialized then return.
125 2.3 Initialize the parent type and then all interfaces implemented
127 2.4 Execute the type initialization code for this type.
128 2.5 Mark the type as initialized, release the initialization lock,
129 awaken any threads waiting for this type to be initialized,
136 guint32 initializing_tid;
137 guint32 waiting_count;
139 CRITICAL_SECTION initialization_section;
140 } TypeInitializationLock;
142 /* for locking access to type_initialization_hash and blocked_thread_hash */
143 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
144 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
145 static CRITICAL_SECTION type_initialization_section;
147 /* from vtable to lock */
148 static GHashTable *type_initialization_hash;
150 /* from thread id to thread id being waited on */
151 static GHashTable *blocked_thread_hash;
154 static MonoThread *main_thread;
156 /* Functions supplied by the runtime */
157 static MonoRuntimeCallbacks callbacks;
160 * mono_thread_set_main:
161 * @thread: thread to set as the main thread
163 * This function can be used to instruct the runtime to treat @thread
164 * as the main thread, ie, the thread that would normally execute the Main()
165 * method. This basically means that at the end of @thread, the runtime will
166 * wait for the existing foreground threads to quit and other such details.
169 mono_thread_set_main (MonoThread *thread)
171 static gboolean registered = FALSE;
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
178 main_thread = thread;
182 mono_thread_get_main (void)
188 mono_type_initialization_init (void)
190 InitializeCriticalSection (&type_initialization_section);
191 type_initialization_hash = g_hash_table_new (NULL, NULL);
192 blocked_thread_hash = g_hash_table_new (NULL, NULL);
193 InitializeCriticalSection (&ldstr_section);
197 mono_type_initialization_cleanup (void)
200 /* This is causing race conditions with
201 * mono_release_type_locks
203 DeleteCriticalSection (&type_initialization_section);
204 g_hash_table_destroy (type_initialization_hash);
205 type_initialization_hash = NULL;
207 DeleteCriticalSection (&ldstr_section);
208 g_hash_table_destroy (blocked_thread_hash);
209 blocked_thread_hash = NULL;
215 * get_type_init_exception_for_vtable:
217 * Return the stored type initialization exception for VTABLE.
219 static MonoException*
220 get_type_init_exception_for_vtable (MonoVTable *vtable)
222 MonoDomain *domain = vtable->domain;
223 MonoClass *klass = vtable->klass;
227 if (!vtable->init_failed)
228 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
231 * If the initializing thread was rudely aborted, the exception is not stored
235 mono_domain_lock (domain);
236 if (domain->type_init_exception_hash)
237 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
238 mono_domain_unlock (domain);
241 if (klass->name_space && *klass->name_space)
242 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
244 full_name = g_strdup (klass->name);
245 ex = mono_get_exception_type_initialization (full_name, NULL);
252 * mono_runtime_class_init:
253 * @vtable: vtable that needs to be initialized
255 * This routine calls the class constructor for @vtable.
258 mono_runtime_class_init (MonoVTable *vtable)
260 mono_runtime_class_init_full (vtable, TRUE);
264 * mono_runtime_class_init_full:
265 * @vtable that neeeds to be initialized
266 * @raise_exception is TRUE, exceptions are raised intead of returned
270 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
273 MonoException *exc_to_throw;
274 MonoMethod *method = NULL;
280 if (vtable->initialized)
284 klass = vtable->klass;
286 if (!klass->image->checked_module_cctor) {
287 mono_image_check_for_module_cctor (klass->image);
288 if (klass->image->has_module_cctor) {
289 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
290 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
293 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
298 method = mono_class_get_cctor (klass);
301 MonoDomain *domain = vtable->domain;
302 TypeInitializationLock *lock;
303 guint32 tid = GetCurrentThreadId();
304 int do_initialization = 0;
305 MonoDomain *last_domain = NULL;
307 mono_type_initialization_lock ();
308 /* double check... */
309 if (vtable->initialized) {
310 mono_type_initialization_unlock ();
313 if (vtable->init_failed) {
314 mono_type_initialization_unlock ();
316 /* The type initialization already failed once, rethrow the same exception */
318 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
319 return get_type_init_exception_for_vtable (vtable);
321 lock = g_hash_table_lookup (type_initialization_hash, vtable);
323 /* This thread will get to do the initialization */
324 if (mono_domain_get () != domain) {
325 /* Transfer into the target domain */
326 last_domain = mono_domain_get ();
327 if (!mono_domain_set (domain, FALSE)) {
328 vtable->initialized = 1;
329 mono_type_initialization_unlock ();
331 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
332 return mono_get_exception_appdomain_unloaded ();
335 lock = g_malloc (sizeof(TypeInitializationLock));
336 InitializeCriticalSection (&lock->initialization_section);
337 lock->initializing_tid = tid;
338 lock->waiting_count = 1;
340 /* grab the vtable lock while this thread still owns type_initialization_section */
341 EnterCriticalSection (&lock->initialization_section);
342 g_hash_table_insert (type_initialization_hash, vtable, lock);
343 do_initialization = 1;
346 TypeInitializationLock *pending_lock;
348 if (lock->initializing_tid == tid || lock->done) {
349 mono_type_initialization_unlock ();
352 /* see if the thread doing the initialization is already blocked on this thread */
353 blocked = GUINT_TO_POINTER (lock->initializing_tid);
354 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
355 if (pending_lock->initializing_tid == tid) {
356 if (!pending_lock->done) {
357 mono_type_initialization_unlock ();
360 /* the thread doing the initialization is blocked on this thread,
361 but on a lock that has already been freed. It just hasn't got
366 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
368 ++lock->waiting_count;
369 /* record the fact that we are waiting on the initializing thread */
370 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
372 mono_type_initialization_unlock ();
374 if (do_initialization) {
375 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
377 /* If the initialization failed, mark the class as unusable. */
378 /* Avoid infinite loops */
380 (klass->image == mono_defaults.corlib &&
381 !strcmp (klass->name_space, "System") &&
382 !strcmp (klass->name, "TypeInitializationException")))) {
383 vtable->init_failed = 1;
385 if (klass->name_space && *klass->name_space)
386 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
388 full_name = g_strdup (klass->name);
389 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
393 * Store the exception object so it could be thrown on subsequent
396 mono_domain_lock (domain);
397 if (!domain->type_init_exception_hash)
398 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
399 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
400 mono_domain_unlock (domain);
404 mono_domain_set (last_domain, TRUE);
406 LeaveCriticalSection (&lock->initialization_section);
408 /* this just blocks until the initializing thread is done */
409 EnterCriticalSection (&lock->initialization_section);
410 LeaveCriticalSection (&lock->initialization_section);
413 mono_type_initialization_lock ();
414 if (lock->initializing_tid != tid)
415 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
416 --lock->waiting_count;
417 if (lock->waiting_count == 0) {
418 DeleteCriticalSection (&lock->initialization_section);
419 g_hash_table_remove (type_initialization_hash, vtable);
422 mono_memory_barrier ();
423 if (!vtable->init_failed)
424 vtable->initialized = 1;
425 mono_type_initialization_unlock ();
427 if (vtable->init_failed) {
428 /* Either we were the initializing thread or we waited for the initialization */
430 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
431 return get_type_init_exception_for_vtable (vtable);
434 vtable->initialized = 1;
441 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
443 MonoVTable *vtable = (MonoVTable*)key;
445 TypeInitializationLock *lock = (TypeInitializationLock*) value;
446 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
449 * Have to set this since it cannot be set by the normal code in
450 * mono_runtime_class_init (). In this case, the exception object is not stored,
451 * and get_type_init_exception_for_class () needs to be aware of this.
453 vtable->init_failed = 1;
454 LeaveCriticalSection (&lock->initialization_section);
455 --lock->waiting_count;
456 if (lock->waiting_count == 0) {
457 DeleteCriticalSection (&lock->initialization_section);
466 mono_release_type_locks (MonoInternalThread *thread)
468 mono_type_initialization_lock ();
469 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
470 mono_type_initialization_unlock ();
474 default_trampoline (MonoMethod *method)
480 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
482 g_assert_not_reached ();
488 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
490 g_error ("remoting not installed");
495 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
497 g_assert_not_reached ();
501 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
502 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
503 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
504 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
505 static MonoImtThunkBuilder imt_thunk_builder = NULL;
506 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
507 #if (MONO_IMT_SIZE > 32)
508 #error "MONO_IMT_SIZE cannot be larger than 32"
512 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
514 memcpy (&callbacks, cbs, sizeof (*cbs));
517 MonoRuntimeCallbacks*
518 mono_get_runtime_callbacks (void)
524 mono_install_trampoline (MonoTrampoline func)
526 arch_create_jit_trampoline = func? func: default_trampoline;
530 mono_install_jump_trampoline (MonoJumpTrampoline func)
532 arch_create_jump_trampoline = func? func: default_jump_trampoline;
536 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
538 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
542 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
544 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
548 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
549 imt_thunk_builder = func;
552 static MonoCompileFunc default_mono_compile_method = NULL;
555 * mono_install_compile_method:
556 * @func: function to install
558 * This is a VM internal routine
561 mono_install_compile_method (MonoCompileFunc func)
563 default_mono_compile_method = func;
567 * mono_compile_method:
568 * @method: The method to compile.
570 * This JIT-compiles the method, and returns the pointer to the native code
574 mono_compile_method (MonoMethod *method)
576 if (!default_mono_compile_method) {
577 g_error ("compile method called on uninitialized runtime");
580 return default_mono_compile_method (method);
584 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
586 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
590 mono_runtime_create_delegate_trampoline (MonoClass *klass)
592 return arch_create_delegate_trampoline (mono_domain_get (), klass);
595 static MonoFreeMethodFunc default_mono_free_method = NULL;
598 * mono_install_free_method:
599 * @func: pointer to the MonoFreeMethodFunc used to release a method
601 * This is an internal VM routine, it is used for the engines to
602 * register a handler to release the resources associated with a method.
604 * Methods are freed when no more references to the delegate that holds
608 mono_install_free_method (MonoFreeMethodFunc func)
610 default_mono_free_method = func;
614 * mono_runtime_free_method:
615 * @domain; domain where the method is hosted
616 * @method: method to release
618 * This routine is invoked to free the resources associated with
619 * a method that has been JIT compiled. This is used to discard
620 * methods that were used only temporarily (for example, used in marshalling)
624 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
626 if (default_mono_free_method != NULL)
627 default_mono_free_method (domain, method);
629 mono_method_clear_object (domain, method);
631 mono_free_method (method);
635 * The vtables in the root appdomain are assumed to be reachable by other
636 * roots, and we don't use typed allocation in the other domains.
639 /* The sync block is no longer a GC pointer */
640 #define GC_HEADER_BITMAP (0)
642 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
645 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
647 MonoClassField *field;
653 max_size = mono_class_data_size (class) / sizeof (gpointer);
655 max_size = class->instance_size / sizeof (gpointer);
656 if (max_size > size) {
657 g_assert (offset <= 0);
658 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
663 /*An Ephemeron cannot be marked by sgen*/
664 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
666 memset (bitmap, 0, size / 8);
671 for (p = class; p != NULL; p = p->parent) {
672 gpointer iter = NULL;
673 while ((field = mono_class_get_fields (p, &iter))) {
677 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
679 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
682 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
685 /* FIXME: should not happen, flag as type load error */
686 if (field->type->byref)
689 if (static_fields && field->offset == -1)
693 pos = field->offset / sizeof (gpointer);
696 type = mono_type_get_underlying_type (field->type);
697 switch (type->type) {
700 case MONO_TYPE_FNPTR:
702 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
707 if (class->image != mono_defaults.corlib)
710 case MONO_TYPE_STRING:
711 case MONO_TYPE_SZARRAY:
712 case MONO_TYPE_CLASS:
713 case MONO_TYPE_OBJECT:
714 case MONO_TYPE_ARRAY:
715 g_assert ((field->offset % sizeof(gpointer)) == 0);
717 g_assert (pos < size || pos <= max_size);
718 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
719 *max_set = MAX (*max_set, pos);
721 case MONO_TYPE_GENERICINST:
722 if (!mono_type_generic_inst_is_valuetype (type)) {
723 g_assert ((field->offset % sizeof(gpointer)) == 0);
725 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
726 *max_set = MAX (*max_set, pos);
731 case MONO_TYPE_VALUETYPE: {
732 MonoClass *fclass = mono_class_from_mono_type (field->type);
733 if (fclass->has_references) {
734 /* remove the object header */
735 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
749 case MONO_TYPE_BOOLEAN:
753 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
764 * mono_class_compute_bitmap:
766 * Mono internal function to compute a bitmap of reference fields in a class.
769 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
771 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
776 * similar to the above, but sets the bits in the bitmap for any non-ref field
777 * and ignores static fields
780 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
782 MonoClassField *field;
787 max_size = class->instance_size / sizeof (gpointer);
788 if (max_size >= size) {
789 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
792 for (p = class; p != NULL; p = p->parent) {
793 gpointer iter = NULL;
794 while ((field = mono_class_get_fields (p, &iter))) {
797 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
799 /* FIXME: should not happen, flag as type load error */
800 if (field->type->byref)
803 pos = field->offset / sizeof (gpointer);
806 type = mono_type_get_underlying_type (field->type);
807 switch (type->type) {
808 #if SIZEOF_VOID_P == 8
812 case MONO_TYPE_FNPTR:
817 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
818 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
819 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
822 #if SIZEOF_VOID_P == 4
826 case MONO_TYPE_FNPTR:
831 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
832 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
833 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
839 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
840 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
841 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
844 case MONO_TYPE_BOOLEAN:
847 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
849 case MONO_TYPE_STRING:
850 case MONO_TYPE_SZARRAY:
851 case MONO_TYPE_CLASS:
852 case MONO_TYPE_OBJECT:
853 case MONO_TYPE_ARRAY:
855 case MONO_TYPE_GENERICINST:
856 if (!mono_type_generic_inst_is_valuetype (type)) {
861 case MONO_TYPE_VALUETYPE: {
862 MonoClass *fclass = mono_class_from_mono_type (field->type);
863 /* remove the object header */
864 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
868 g_assert_not_reached ();
877 * mono_class_insecure_overlapping:
878 * check if a class with explicit layout has references and non-references
879 * fields overlapping.
881 * Returns: TRUE if it is insecure to load the type.
884 mono_class_insecure_overlapping (MonoClass *klass)
888 gsize default_bitmap [4] = {0};
890 gsize default_nrbitmap [4] = {0};
891 int i, insecure = FALSE;
894 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
895 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
897 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
898 int idx = i % (sizeof (bitmap [0]) * 8);
899 if (bitmap [idx] & nrbitmap [idx]) {
904 if (bitmap != default_bitmap)
906 if (nrbitmap != default_nrbitmap)
909 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
917 mono_string_alloc (int length)
919 return mono_string_new_size (mono_domain_get (), length);
923 mono_class_compute_gc_descriptor (MonoClass *class)
927 gsize default_bitmap [4] = {0};
928 static gboolean gcj_inited = FALSE;
933 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
934 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
935 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
936 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
938 #ifdef HAVE_GC_GCJ_MALLOC
940 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
944 #ifdef GC_REDIRECT_TO_LOCAL
945 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
946 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
948 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
949 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
954 mono_loader_unlock ();
958 mono_class_init (class);
960 if (class->gc_descr_inited)
963 class->gc_descr_inited = TRUE;
964 class->gc_descr = GC_NO_DESCRIPTOR;
966 bitmap = default_bitmap;
967 if (class == mono_defaults.string_class) {
968 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
969 } else if (class->rank) {
970 mono_class_compute_gc_descriptor (class->element_class);
971 if (!class->element_class->valuetype) {
973 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
974 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
975 class->name_space, class->name);*/
977 /* remove the object header */
978 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
979 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
980 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
981 class->name_space, class->name);*/
982 if (bitmap != default_bitmap)
986 /*static int count = 0;
989 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
990 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
992 if (class->gc_descr == GC_NO_DESCRIPTOR)
993 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
995 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
996 if (bitmap != default_bitmap)
1002 * field_is_special_static:
1003 * @fklass: The MonoClass to look up.
1004 * @field: The MonoClassField describing the field.
1006 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1007 * SPECIAL_STATIC_NONE otherwise.
1010 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1012 MonoCustomAttrInfo *ainfo;
1014 ainfo = mono_custom_attrs_from_field (fklass, field);
1017 for (i = 0; i < ainfo->num_attrs; ++i) {
1018 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1019 if (klass->image == mono_defaults.corlib) {
1020 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1021 mono_custom_attrs_free (ainfo);
1022 return SPECIAL_STATIC_THREAD;
1024 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1025 mono_custom_attrs_free (ainfo);
1026 return SPECIAL_STATIC_CONTEXT;
1030 mono_custom_attrs_free (ainfo);
1031 return SPECIAL_STATIC_NONE;
1034 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1035 #define mix(a,b,c) { \
1036 a -= c; a ^= rot(c, 4); c += b; \
1037 b -= a; b ^= rot(a, 6); a += c; \
1038 c -= b; c ^= rot(b, 8); b += a; \
1039 a -= c; a ^= rot(c,16); c += b; \
1040 b -= a; b ^= rot(a,19); a += c; \
1041 c -= b; c ^= rot(b, 4); b += a; \
1043 #define final(a,b,c) { \
1044 c ^= b; c -= rot(b,14); \
1045 a ^= c; a -= rot(c,11); \
1046 b ^= a; b -= rot(a,25); \
1047 c ^= b; c -= rot(b,16); \
1048 a ^= c; a -= rot(c,4); \
1049 b ^= a; b -= rot(a,14); \
1050 c ^= b; c -= rot(b,24); \
1054 * mono_method_get_imt_slot:
1056 * The IMT slot is embedded into AOTed code, so this must return the same value
1057 * for the same method across all executions. This means:
1058 * - pointers shouldn't be used as hash values.
1059 * - mono_metadata_str_hash () should be used for hashing strings.
1062 mono_method_get_imt_slot (MonoMethod *method)
1064 MonoMethodSignature *sig;
1066 guint32 *hashes_start, *hashes;
1070 /* This can be used to stress tests the collision code */
1074 * We do this to simplify generic sharing. It will hurt
1075 * performance in cases where a class implements two different
1076 * instantiations of the same generic interface.
1077 * The code in build_imt_slots () depends on this.
1079 if (method->is_inflated)
1080 method = ((MonoMethodInflated*)method)->declaring;
1082 sig = mono_method_signature (method);
1083 hashes_count = sig->param_count + 4;
1084 hashes_start = malloc (hashes_count * sizeof (guint32));
1085 hashes = hashes_start;
1087 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1088 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1089 method->klass->name_space, method->klass->name, method->name);
1092 /* Initialize hashes */
1093 hashes [0] = mono_metadata_str_hash (method->klass->name);
1094 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1095 hashes [2] = mono_metadata_str_hash (method->name);
1096 hashes [3] = mono_metadata_type_hash (sig->ret);
1097 for (i = 0; i < sig->param_count; i++) {
1098 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1101 /* Setup internal state */
1102 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1104 /* Handle most of the hashes */
1105 while (hashes_count > 3) {
1114 /* Handle the last 3 hashes (all the case statements fall through) */
1115 switch (hashes_count) {
1116 case 3 : c += hashes [2];
1117 case 2 : b += hashes [1];
1118 case 1 : a += hashes [0];
1120 case 0: /* nothing left to add */
1124 free (hashes_start);
1125 /* Report the result */
1126 return c % MONO_IMT_SIZE;
1135 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1136 guint32 imt_slot = mono_method_get_imt_slot (method);
1137 MonoImtBuilderEntry *entry;
1139 if (slot_num >= 0 && imt_slot != slot_num) {
1140 /* we build just a single imt slot and this is not it */
1144 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1145 entry->key = method;
1146 entry->value.vtable_slot = vtable_slot;
1147 entry->next = imt_builder [imt_slot];
1148 if (imt_builder [imt_slot] != NULL) {
1149 entry->children = imt_builder [imt_slot]->children + 1;
1150 if (entry->children == 1) {
1151 mono_stats.imt_slots_with_collisions++;
1152 *imt_collisions_bitmap |= (1 << imt_slot);
1155 entry->children = 0;
1156 mono_stats.imt_used_slots++;
1158 imt_builder [imt_slot] = entry;
1161 char *method_name = mono_method_full_name (method, TRUE);
1162 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1163 method, method_name, imt_slot, vtable_slot, entry->children);
1164 g_free (method_name);
1171 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1173 MonoMethod *method = e->key;
1174 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1178 method->klass->name_space,
1179 method->klass->name,
1182 printf (" * %s: NULL\n", message);
1188 compare_imt_builder_entries (const void *p1, const void *p2) {
1189 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1190 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1192 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1196 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1198 int count = end - start;
1199 int chunk_start = out_array->len;
1202 for (i = start; i < end; ++i) {
1203 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1204 item->key = sorted_array [i]->key;
1205 item->value = sorted_array [i]->value;
1206 item->has_target_code = sorted_array [i]->has_target_code;
1207 item->is_equals = TRUE;
1209 item->check_target_idx = out_array->len + 1;
1211 item->check_target_idx = 0;
1212 g_ptr_array_add (out_array, item);
1215 int middle = start + count / 2;
1216 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1218 item->key = sorted_array [middle]->key;
1219 item->is_equals = FALSE;
1220 g_ptr_array_add (out_array, item);
1221 imt_emit_ir (sorted_array, start, middle, out_array);
1222 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1228 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1229 int number_of_entries = entries->children + 1;
1230 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1231 GPtrArray *result = g_ptr_array_new ();
1232 MonoImtBuilderEntry *current_entry;
1235 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1236 sorted_array [i] = current_entry;
1238 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1240 /*for (i = 0; i < number_of_entries; i++) {
1241 print_imt_entry (" sorted array:", sorted_array [i], i);
1244 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1246 free (sorted_array);
1251 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1253 if (imt_builder_entry != NULL) {
1254 if (imt_builder_entry->children == 0 && !fail_tramp) {
1255 /* No collision, return the vtable slot contents */
1256 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1258 /* Collision, build the thunk */
1259 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1262 result = imt_thunk_builder (vtable, domain,
1263 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1264 for (i = 0; i < imt_ir->len; ++i)
1265 g_free (g_ptr_array_index (imt_ir, i));
1266 g_ptr_array_free (imt_ir, TRUE);
1278 static MonoImtBuilderEntry*
1279 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1282 * LOCKING: requires the loader and domain locks.
1286 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1290 guint32 imt_collisions_bitmap = 0;
1291 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1292 int method_count = 0;
1293 gboolean record_method_count_for_max_collisions = FALSE;
1294 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1297 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1299 for (i = 0; i < klass->interface_offsets_count; ++i) {
1300 MonoClass *iface = klass->interfaces_packed [i];
1301 int interface_offset = klass->interface_offsets_packed [i];
1302 int method_slot_in_interface, vt_slot;
1304 if (mono_class_has_variant_generic_params (iface))
1305 has_variant_iface = TRUE;
1307 vt_slot = interface_offset;
1308 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1311 if (slot_num >= 0 && iface->is_inflated) {
1313 * The imt slot of the method is the same as for its declaring method,
1314 * see the comment in mono_method_get_imt_slot (), so we can
1315 * avoid inflating methods which will be discarded by
1316 * add_imt_builder_entry anyway.
1318 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1319 if (mono_method_get_imt_slot (method) != slot_num) {
1324 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1325 if (method->is_generic) {
1326 has_generic_virtual = TRUE;
1331 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1332 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1337 if (extra_interfaces) {
1338 int interface_offset = klass->vtable_size;
1340 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1341 MonoClass* iface = list_item->data;
1342 int method_slot_in_interface;
1343 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1344 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1345 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1347 interface_offset += iface->method.count;
1350 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1351 /* overwrite the imt slot only if we're building all the entries or if
1352 * we're building this specific one
1354 if (slot_num < 0 || i == slot_num) {
1355 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1358 if (imt_builder [i]) {
1359 MonoImtBuilderEntry *entry;
1361 /* Link entries with imt_builder [i] */
1362 for (entry = entries; entry->next; entry = entry->next) {
1364 MonoMethod *method = (MonoMethod*)entry->key;
1365 char *method_name = mono_method_full_name (method, TRUE);
1366 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1367 g_free (method_name);
1370 entry->next = imt_builder [i];
1371 entries->children += imt_builder [i]->children + 1;
1373 imt_builder [i] = entries;
1376 if (has_generic_virtual || has_variant_iface) {
1378 * There might be collisions later when the the thunk is expanded.
1380 imt_collisions_bitmap |= (1 << i);
1383 * The IMT thunk might be called with an instance of one of the
1384 * generic virtual methods, so has to fallback to the IMT trampoline.
1386 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1388 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1391 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1395 if (imt_builder [i] != NULL) {
1396 int methods_in_slot = imt_builder [i]->children + 1;
1397 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1398 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1399 record_method_count_for_max_collisions = TRUE;
1401 method_count += methods_in_slot;
1405 mono_stats.imt_number_of_methods += method_count;
1406 if (record_method_count_for_max_collisions) {
1407 mono_stats.imt_method_count_when_max_collisions = method_count;
1410 for (i = 0; i < MONO_IMT_SIZE; i++) {
1411 MonoImtBuilderEntry* entry = imt_builder [i];
1412 while (entry != NULL) {
1413 MonoImtBuilderEntry* next = entry->next;
1419 /* we OR the bitmap since we may build just a single imt slot at a time */
1420 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1424 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1425 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1429 * mono_vtable_build_imt_slot:
1430 * @vtable: virtual object table struct
1431 * @imt_slot: slot in the IMT table
1433 * Fill the given @imt_slot in the IMT table of @vtable with
1434 * a trampoline or a thunk for the case of collisions.
1435 * This is part of the internal mono API.
1437 * LOCKING: Take the domain lock.
1440 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1442 gpointer *imt = (gpointer*)vtable;
1443 imt -= MONO_IMT_SIZE;
1444 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1446 /* no support for extra interfaces: the proxy objects will need
1447 * to build the complete IMT
1448 * Update and heck needs to ahppen inside the proper domain lock, as all
1449 * the changes made to a MonoVTable.
1451 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1452 mono_domain_lock (vtable->domain);
1453 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1454 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1455 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1456 mono_domain_unlock (vtable->domain);
1457 mono_loader_unlock ();
1462 * The first two free list entries both belong to the wait list: The
1463 * first entry is the pointer to the head of the list and the second
1464 * entry points to the last element. That way appending and removing
1465 * the first element are both O(1) operations.
1467 #ifdef MONO_SMALL_CONFIG
1468 #define NUM_FREE_LISTS 6
1470 #define NUM_FREE_LISTS 12
1472 #define FIRST_FREE_LIST_SIZE 64
1473 #define MAX_WAIT_LENGTH 50
1474 #define THUNK_THRESHOLD 10
1477 * LOCKING: The domain lock must be held.
1480 init_thunk_free_lists (MonoDomain *domain)
1482 if (domain->thunk_free_lists)
1484 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1488 list_index_for_size (int item_size)
1491 int size = FIRST_FREE_LIST_SIZE;
1493 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1502 * mono_method_alloc_generic_virtual_thunk:
1504 * @size: size in bytes
1506 * Allocs size bytes to be used for the code of a generic virtual
1507 * thunk. It's either allocated from the domain's code manager or
1508 * reused from a previously invalidated piece.
1510 * LOCKING: The domain lock must be held.
1513 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1515 static gboolean inited = FALSE;
1516 static int generic_virtual_thunks_size = 0;
1520 MonoThunkFreeList **l;
1522 init_thunk_free_lists (domain);
1524 size += sizeof (guint32);
1525 if (size < sizeof (MonoThunkFreeList))
1526 size = sizeof (MonoThunkFreeList);
1528 i = list_index_for_size (size);
1529 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1530 if ((*l)->size >= size) {
1531 MonoThunkFreeList *item = *l;
1533 return ((guint32*)item) + 1;
1537 /* no suitable item found - search lists of larger sizes */
1538 while (++i < NUM_FREE_LISTS) {
1539 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1542 g_assert (item->size > size);
1543 domain->thunk_free_lists [i] = item->next;
1544 return ((guint32*)item) + 1;
1547 /* still nothing found - allocate it */
1549 mono_counters_register ("Generic virtual thunk bytes",
1550 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1553 generic_virtual_thunks_size += size;
1555 p = mono_domain_code_reserve (domain, size);
1558 mono_domain_lock (domain);
1559 if (!domain->generic_virtual_thunks)
1560 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1561 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1562 mono_domain_unlock (domain);
1568 * LOCKING: The domain lock must be held.
1571 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1574 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1575 gboolean found = FALSE;
1577 mono_domain_lock (domain);
1578 if (!domain->generic_virtual_thunks)
1579 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1580 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1582 mono_domain_unlock (domain);
1585 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1587 init_thunk_free_lists (domain);
1589 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1590 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1591 int length = item->length;
1594 /* unlink the first item from the wait list */
1595 domain->thunk_free_lists [0] = item->next;
1596 domain->thunk_free_lists [0]->length = length - 1;
1598 i = list_index_for_size (item->size);
1600 /* put it in the free list */
1601 item->next = domain->thunk_free_lists [i];
1602 domain->thunk_free_lists [i] = item;
1606 if (domain->thunk_free_lists [1]) {
1607 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1608 domain->thunk_free_lists [0]->length++;
1610 g_assert (!domain->thunk_free_lists [0]);
1612 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1613 domain->thunk_free_lists [0]->length = 1;
1617 typedef struct _GenericVirtualCase {
1621 struct _GenericVirtualCase *next;
1622 } GenericVirtualCase;
1625 * get_generic_virtual_entries:
1627 * Return IMT entries for the generic virtual method instances and
1628 * variant interface methods for vtable slot
1631 static MonoImtBuilderEntry*
1632 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1634 GenericVirtualCase *list;
1635 MonoImtBuilderEntry *entries;
1637 mono_domain_lock (domain);
1638 if (!domain->generic_virtual_cases)
1639 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1641 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1644 for (; list; list = list->next) {
1645 MonoImtBuilderEntry *entry;
1647 if (list->count < THUNK_THRESHOLD)
1650 entry = g_new0 (MonoImtBuilderEntry, 1);
1651 entry->key = list->method;
1652 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1653 entry->has_target_code = 1;
1655 entry->children = entries->children + 1;
1656 entry->next = entries;
1660 mono_domain_unlock (domain);
1662 /* FIXME: Leaking memory ? */
1667 * mono_method_add_generic_virtual_invocation:
1669 * @vtable_slot: pointer to the vtable slot
1670 * @method: the inflated generic virtual method
1671 * @code: the method's code
1673 * Registers a call via unmanaged code to a generic virtual method
1674 * instantiation or variant interface method. If the number of calls reaches a threshold
1675 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1676 * virtual method thunk.
1679 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1680 gpointer *vtable_slot,
1681 MonoMethod *method, gpointer code)
1683 static gboolean inited = FALSE;
1684 static int num_added = 0;
1686 GenericVirtualCase *gvc, *list;
1687 MonoImtBuilderEntry *entries;
1691 mono_domain_lock (domain);
1692 if (!domain->generic_virtual_cases)
1693 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1695 /* Check whether the case was already added */
1696 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1699 if (gvc->method == method)
1704 /* If not found, make a new one */
1706 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1707 gvc->method = method;
1710 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1712 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1715 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1721 if (++gvc->count == THUNK_THRESHOLD) {
1722 gpointer *old_thunk = *vtable_slot;
1723 gpointer vtable_trampoline = NULL;
1724 gpointer imt_trampoline = NULL;
1726 if ((gpointer)vtable_slot < (gpointer)vtable) {
1727 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1728 int imt_slot = MONO_IMT_SIZE + displacement;
1730 /* Force the rebuild of the thunk at the next call */
1731 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1732 *vtable_slot = imt_trampoline;
1734 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1736 entries = get_generic_virtual_entries (domain, vtable_slot);
1738 sorted = imt_sort_slot_entries (entries);
1740 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1744 MonoImtBuilderEntry *next = entries->next;
1749 for (i = 0; i < sorted->len; ++i)
1750 g_free (g_ptr_array_index (sorted, i));
1751 g_ptr_array_free (sorted, TRUE);
1754 #ifndef __native_client__
1755 /* We don't re-use any thunks as there is a lot of overhead */
1756 /* to deleting and re-using code in Native Client. */
1757 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1758 invalidate_generic_virtual_thunk (domain, old_thunk);
1762 mono_domain_unlock (domain);
1765 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1768 * mono_class_vtable:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1772 * VTables are domain specific because we create domain specific code, and
1773 * they contain the domain specific static class data.
1774 * On failure, NULL is returned, and class->exception_type is set.
1777 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1779 return mono_class_vtable_full (domain, class, FALSE);
1783 * mono_class_vtable_full:
1784 * @domain: the application domain
1785 * @class: the class to initialize
1786 * @raise_on_error if an exception should be raised on failure or not
1788 * VTables are domain specific because we create domain specific code, and
1789 * they contain the domain specific static class data.
1792 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1794 MonoClassRuntimeInfo *runtime_info;
1798 if (class->exception_type) {
1800 mono_raise_exception (mono_class_get_exception_for_failure (class));
1804 /* this check can be inlined in jitted code, too */
1805 runtime_info = class->runtime_info;
1806 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1807 return runtime_info->domain_vtables [domain->domain_id];
1808 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1812 * mono_class_try_get_vtable:
1813 * @domain: the application domain
1814 * @class: the class to initialize
1816 * This function tries to get the associated vtable from @class if
1817 * it was already created.
1820 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1822 MonoClassRuntimeInfo *runtime_info;
1826 runtime_info = class->runtime_info;
1827 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1828 return runtime_info->domain_vtables [domain->domain_id];
1833 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1836 MonoClassRuntimeInfo *runtime_info, *old_info;
1837 MonoClassField *field;
1839 int i, vtable_slots;
1840 int imt_table_bytes = 0;
1842 guint32 vtable_size, class_size;
1845 gpointer *interface_offsets;
1847 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1848 mono_domain_lock (domain);
1849 runtime_info = class->runtime_info;
1850 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1851 mono_domain_unlock (domain);
1852 mono_loader_unlock ();
1853 return runtime_info->domain_vtables [domain->domain_id];
1855 if (!class->inited || class->exception_type) {
1856 if (!mono_class_init (class) || class->exception_type) {
1857 mono_domain_unlock (domain);
1858 mono_loader_unlock ();
1860 mono_raise_exception (mono_class_get_exception_for_failure (class));
1865 /* Array types require that their element type be valid*/
1866 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1867 MonoClass *element_class = class->element_class;
1868 if (!element_class->inited)
1869 mono_class_init (element_class);
1871 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1872 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1873 mono_class_setup_vtable (element_class);
1875 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1876 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1877 if (class->exception_type == MONO_EXCEPTION_NONE)
1878 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1879 mono_domain_unlock (domain);
1880 mono_loader_unlock ();
1882 mono_raise_exception (mono_class_get_exception_for_failure (class));
1888 * For some classes, mono_class_init () already computed class->vtable_size, and
1889 * that is all that is needed because of the vtable trampolines.
1891 if (!class->vtable_size)
1892 mono_class_setup_vtable (class);
1894 if (class->generic_class && !class->vtable)
1895 mono_class_check_vtable_constraints (class, NULL);
1897 /* Initialize klass->has_finalize */
1898 mono_class_has_finalizer (class);
1900 if (class->exception_type) {
1901 mono_domain_unlock (domain);
1902 mono_loader_unlock ();
1904 mono_raise_exception (mono_class_get_exception_for_failure (class));
1908 vtable_slots = class->vtable_size;
1909 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1910 class_size = mono_class_data_size (class);
1915 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1916 if (class->interface_offsets_count) {
1917 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1918 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1919 mono_stats.imt_number_of_tables++;
1920 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1923 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1924 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1927 mono_stats.used_class_count++;
1928 mono_stats.class_vtable_size += vtable_size;
1929 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1932 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1934 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1936 vt->rank = class->rank;
1937 vt->domain = domain;
1939 mono_class_compute_gc_descriptor (class);
1941 * We can't use typed allocation in the non-root domains, since the
1942 * collector needs the GC descriptor stored in the vtable even after
1943 * the mempool containing the vtable is destroyed when the domain is
1944 * unloaded. An alternative might be to allocate vtables in the GC
1945 * heap, but this does not seem to work (it leads to crashes inside
1946 * libgc). If that approach is tried, two gc descriptors need to be
1947 * allocated for each class: one for the root domain, and one for all
1948 * other domains. The second descriptor should contain a bit for the
1949 * vtable field in MonoObject, since we can no longer assume the
1950 * vtable is reachable by other roots after the appdomain is unloaded.
1952 #ifdef HAVE_BOEHM_GC
1953 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1954 vt->gc_descr = GC_NO_DESCRIPTOR;
1957 vt->gc_descr = class->gc_descr;
1959 gc_bits = mono_gc_get_vtable_bits (class);
1960 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1962 vt->gc_bits = gc_bits;
1965 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1966 if (class->has_static_refs) {
1967 gpointer statics_gc_descr;
1969 gsize default_bitmap [4] = {0};
1972 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1973 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1974 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1975 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1976 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1977 if (bitmap != default_bitmap)
1980 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1982 vt->has_static_fields = TRUE;
1983 mono_stats.class_static_data_size += class_size;
1988 while ((field = mono_class_get_fields (class, &iter))) {
1989 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1991 if (mono_field_is_deleted (field))
1993 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1994 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1995 if (special_static != SPECIAL_STATIC_NONE) {
1996 guint32 size, offset;
1998 gsize default_bitmap [4] = {0};
2002 if (mono_type_is_reference (field->type)) {
2003 default_bitmap [0] = 1;
2005 bitmap = default_bitmap;
2006 } else if (mono_type_is_struct (field->type)) {
2007 fclass = mono_class_from_mono_type (field->type);
2008 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2010 default_bitmap [0] = 0;
2012 bitmap = default_bitmap;
2014 size = mono_type_size (field->type, &align);
2015 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2016 if (!domain->special_static_fields)
2017 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2018 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2019 if (bitmap != default_bitmap)
2022 * This marks the field as special static to speed up the
2023 * checks in mono_field_static_get/set_value ().
2029 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2030 MonoClass *fklass = mono_class_from_mono_type (field->type);
2031 const char *data = mono_field_get_data (field);
2033 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2034 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2035 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2038 if (fklass->valuetype) {
2039 memcpy (t, data, mono_class_value_size (fklass, NULL));
2041 /* it's a pointer type: add check */
2042 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2049 vt->max_interface_id = class->max_interface_id;
2050 vt->interface_bitmap = class->interface_bitmap;
2052 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2053 // class->name, class->interface_offsets_count);
2055 if (! ARCH_USE_IMT) {
2056 /* initialize interface offsets */
2057 for (i = 0; i < class->interface_offsets_count; ++i) {
2058 int interface_id = class->interfaces_packed [i]->interface_id;
2059 int slot = class->interface_offsets_packed [i];
2060 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2064 /* Initialize vtable */
2065 if (callbacks.get_vtable_trampoline) {
2066 // This also covers the AOT case
2067 for (i = 0; i < class->vtable_size; ++i) {
2068 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2071 mono_class_setup_vtable (class);
2073 for (i = 0; i < class->vtable_size; ++i) {
2076 if ((cm = class->vtable [i]))
2077 vt->vtable [i] = arch_create_jit_trampoline (cm);
2081 if (ARCH_USE_IMT && imt_table_bytes) {
2082 /* Now that the vtable is full, we can actually fill up the IMT */
2083 if (callbacks.get_imt_trampoline) {
2084 /* lazy construction of the IMT entries enabled */
2085 for (i = 0; i < MONO_IMT_SIZE; ++i)
2086 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2088 build_imt (class, vt, domain, interface_offsets, NULL);
2093 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2094 * re-acquire them and check if another thread has created the vtable in the meantime.
2096 /* Special case System.MonoType to avoid infinite recursion */
2097 if (class != mono_defaults.monotype_class) {
2098 /*FIXME check for OOM*/
2099 vt->type = mono_type_get_object (domain, &class->byval_arg);
2100 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2101 /* This is unregistered in
2102 unregister_vtable_reflection_type() in
2104 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2107 if (class->contextbound)
2112 /* class_vtable_array keeps an array of created vtables
2114 g_ptr_array_add (domain->class_vtable_array, vt);
2115 /* class->runtime_info is protected by the loader lock, both when
2116 * it it enlarged and when it is stored info.
2120 * Store the vtable in class->runtime_info.
2121 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2123 mono_memory_barrier ();
2125 old_info = class->runtime_info;
2126 if (old_info && old_info->max_domain >= domain->domain_id) {
2127 /* someone already created a large enough runtime info */
2128 old_info->domain_vtables [domain->domain_id] = vt;
2130 int new_size = domain->domain_id;
2132 new_size = MAX (new_size, old_info->max_domain);
2134 /* make the new size a power of two */
2136 while (new_size > i)
2139 /* this is a bounded memory retention issue: may want to
2140 * handle it differently when we'll have a rcu-like system.
2142 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2143 runtime_info->max_domain = new_size - 1;
2144 /* copy the stuff from the older info */
2146 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2148 runtime_info->domain_vtables [domain->domain_id] = vt;
2150 mono_memory_barrier ();
2151 class->runtime_info = runtime_info;
2154 if (class == mono_defaults.monotype_class) {
2155 /*FIXME check for OOM*/
2156 vt->type = mono_type_get_object (domain, &class->byval_arg);
2157 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2158 /* This is unregistered in
2159 unregister_vtable_reflection_type() in
2161 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2164 mono_domain_unlock (domain);
2165 mono_loader_unlock ();
2167 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2168 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2169 mono_raise_exception (mono_class_get_exception_for_failure (class));
2171 /* make sure the parent is initialized */
2172 /*FIXME shouldn't this fail the current type?*/
2174 mono_class_vtable_full (domain, class->parent, raise_on_error);
2180 * mono_class_proxy_vtable:
2181 * @domain: the application domain
2182 * @remove_class: the remote class
2184 * Creates a vtable for transparent proxies. It is basically
2185 * a copy of the real vtable of the class wrapped in @remote_class,
2186 * but all function pointers invoke the remoting functions, and
2187 * vtable->klass points to the transparent proxy class, and not to @class.
2190 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2193 MonoVTable *vt, *pvt;
2194 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2196 GSList *extra_interfaces = NULL;
2197 MonoClass *class = remote_class->proxy_class;
2198 gpointer *interface_offsets;
2202 #ifdef COMPRESSED_INTERFACE_BITMAP
2206 vt = mono_class_vtable (domain, class);
2207 g_assert (vt); /*FIXME property handle failure*/
2208 max_interface_id = vt->max_interface_id;
2210 /* Calculate vtable space for extra interfaces */
2211 for (j = 0; j < remote_class->interface_count; j++) {
2212 MonoClass* iclass = remote_class->interfaces[j];
2216 /*FIXME test for interfaces with variant generic arguments*/
2217 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2218 continue; /* interface implemented by the class */
2219 if (g_slist_find (extra_interfaces, iclass))
2222 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2224 method_count = mono_class_num_methods (iclass);
2226 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2227 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2229 for (i = 0; i < ifaces->len; ++i) {
2230 MonoClass *ic = g_ptr_array_index (ifaces, i);
2231 /*FIXME test for interfaces with variant generic arguments*/
2232 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2233 continue; /* interface implemented by the class */
2234 if (g_slist_find (extra_interfaces, ic))
2236 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2237 method_count += mono_class_num_methods (ic);
2239 g_ptr_array_free (ifaces, TRUE);
2242 extra_interface_vtsize += method_count * sizeof (gpointer);
2243 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2247 mono_stats.imt_number_of_tables++;
2248 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2249 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2250 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2252 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2253 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2256 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2258 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2260 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2262 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2263 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2265 pvt->klass = mono_defaults.transparent_proxy_class;
2266 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2267 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2269 /* initialize vtable */
2270 mono_class_setup_vtable (class);
2271 for (i = 0; i < class->vtable_size; ++i) {
2274 if ((cm = class->vtable [i]))
2275 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2277 pvt->vtable [i] = NULL;
2280 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2281 /* create trampolines for abstract methods */
2282 for (k = class; k; k = k->parent) {
2284 gpointer iter = NULL;
2285 while ((m = mono_class_get_methods (k, &iter)))
2286 if (!pvt->vtable [m->slot])
2287 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2291 pvt->max_interface_id = max_interface_id;
2292 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2293 #ifdef COMPRESSED_INTERFACE_BITMAP
2294 bitmap = g_malloc0 (bsize);
2296 bitmap = mono_domain_alloc0 (domain, bsize);
2299 if (! ARCH_USE_IMT) {
2300 /* initialize interface offsets */
2301 for (i = 0; i < class->interface_offsets_count; ++i) {
2302 int interface_id = class->interfaces_packed [i]->interface_id;
2303 int slot = class->interface_offsets_packed [i];
2304 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2307 for (i = 0; i < class->interface_offsets_count; ++i) {
2308 int interface_id = class->interfaces_packed [i]->interface_id;
2309 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2312 if (extra_interfaces) {
2313 int slot = class->vtable_size;
2319 /* Create trampolines for the methods of the interfaces */
2320 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2321 interf = list_item->data;
2323 if (! ARCH_USE_IMT) {
2324 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2326 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2330 while ((cm = mono_class_get_methods (interf, &iter)))
2331 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2333 slot += mono_class_num_methods (interf);
2335 if (! ARCH_USE_IMT) {
2336 g_slist_free (extra_interfaces);
2341 /* Now that the vtable is full, we can actually fill up the IMT */
2342 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2343 if (extra_interfaces) {
2344 g_slist_free (extra_interfaces);
2348 #ifdef COMPRESSED_INTERFACE_BITMAP
2349 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2350 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2351 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2354 pvt->interface_bitmap = bitmap;
2360 * mono_class_field_is_special_static:
2362 * Returns whether @field is a thread/context static field.
2365 mono_class_field_is_special_static (MonoClassField *field)
2367 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2369 if (mono_field_is_deleted (field))
2371 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2372 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2379 * mono_class_field_get_special_static_type:
2380 * @field: The MonoClassField describing the field.
2382 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2383 * SPECIAL_STATIC_NONE otherwise.
2386 mono_class_field_get_special_static_type (MonoClassField *field)
2388 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2389 return SPECIAL_STATIC_NONE;
2390 if (mono_field_is_deleted (field))
2391 return SPECIAL_STATIC_NONE;
2392 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2393 return field_is_special_static (field->parent, field);
2394 return SPECIAL_STATIC_NONE;
2398 * mono_class_has_special_static_fields:
2400 * Returns whenever @klass has any thread/context static fields.
2403 mono_class_has_special_static_fields (MonoClass *klass)
2405 MonoClassField *field;
2409 while ((field = mono_class_get_fields (klass, &iter))) {
2410 g_assert (field->parent == klass);
2411 if (mono_class_field_is_special_static (field))
2419 * create_remote_class_key:
2420 * Creates an array of pointers that can be used as a hash key for a remote class.
2421 * The first element of the array is the number of pointers.
2424 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2429 if (remote_class == NULL) {
2430 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2431 key = g_malloc (sizeof(gpointer) * 3);
2432 key [0] = GINT_TO_POINTER (2);
2433 key [1] = mono_defaults.marshalbyrefobject_class;
2434 key [2] = extra_class;
2436 key = g_malloc (sizeof(gpointer) * 2);
2437 key [0] = GINT_TO_POINTER (1);
2438 key [1] = extra_class;
2441 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2442 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2443 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2444 key [1] = remote_class->proxy_class;
2446 // Keep the list of interfaces sorted
2447 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2448 if (extra_class && remote_class->interfaces [i] > extra_class) {
2449 key [j++] = extra_class;
2452 key [j] = remote_class->interfaces [i];
2455 key [j] = extra_class;
2457 // Replace the old class. The interface list is the same
2458 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2459 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2460 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2461 for (i = 0; i < remote_class->interface_count; i++)
2462 key [2 + i] = remote_class->interfaces [i];
2470 * copy_remote_class_key:
2472 * Make a copy of KEY in the domain and return the copy.
2475 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2477 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2478 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2480 memcpy (mp_key, key, key_size);
2486 * mono_remote_class:
2487 * @domain: the application domain
2488 * @class_name: name of the remote class
2490 * Creates and initializes a MonoRemoteClass object for a remote type.
2492 * Can raise an exception on failure.
2495 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2498 MonoRemoteClass *rc;
2499 gpointer* key, *mp_key;
2502 key = create_remote_class_key (NULL, proxy_class);
2504 mono_domain_lock (domain);
2505 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2509 mono_domain_unlock (domain);
2513 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2514 if (!mono_error_ok (&error)) {
2516 mono_domain_unlock (domain);
2517 mono_error_raise_exception (&error);
2520 mp_key = copy_remote_class_key (domain, key);
2524 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2525 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2526 rc->interface_count = 1;
2527 rc->interfaces [0] = proxy_class;
2528 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2530 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2531 rc->interface_count = 0;
2532 rc->proxy_class = proxy_class;
2535 rc->default_vtable = NULL;
2536 rc->xdomain_vtable = NULL;
2537 rc->proxy_class_name = name;
2538 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2540 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2542 mono_domain_unlock (domain);
2547 * clone_remote_class:
2548 * Creates a copy of the remote_class, adding the provided class or interface
2550 static MonoRemoteClass*
2551 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2553 MonoRemoteClass *rc;
2554 gpointer* key, *mp_key;
2556 key = create_remote_class_key (remote_class, extra_class);
2557 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2563 mp_key = copy_remote_class_key (domain, key);
2567 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2569 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2570 rc->proxy_class = remote_class->proxy_class;
2571 rc->interface_count = remote_class->interface_count + 1;
2573 // Keep the list of interfaces sorted, since the hash key of
2574 // the remote class depends on this
2575 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2576 if (remote_class->interfaces [i] > extra_class && i == j)
2577 rc->interfaces [j++] = extra_class;
2578 rc->interfaces [j] = remote_class->interfaces [i];
2581 rc->interfaces [j] = extra_class;
2583 // Replace the old class. The interface array is the same
2584 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2585 rc->proxy_class = extra_class;
2586 rc->interface_count = remote_class->interface_count;
2587 if (rc->interface_count > 0)
2588 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2591 rc->default_vtable = NULL;
2592 rc->xdomain_vtable = NULL;
2593 rc->proxy_class_name = remote_class->proxy_class_name;
2595 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2601 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2603 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2604 mono_domain_lock (domain);
2605 if (rp->target_domain_id != -1) {
2606 if (remote_class->xdomain_vtable == NULL)
2607 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2608 mono_domain_unlock (domain);
2609 mono_loader_unlock ();
2610 return remote_class->xdomain_vtable;
2612 if (remote_class->default_vtable == NULL) {
2615 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2616 klass = mono_class_from_mono_type (type);
2617 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2618 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2620 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2623 mono_domain_unlock (domain);
2624 mono_loader_unlock ();
2625 return remote_class->default_vtable;
2629 * mono_upgrade_remote_class:
2630 * @domain: the application domain
2631 * @tproxy: the proxy whose remote class has to be upgraded.
2632 * @klass: class to which the remote class can be casted.
2634 * Updates the vtable of the remote class by adding the necessary method slots
2635 * and interface offsets so it can be safely casted to klass. klass can be a
2636 * class or an interface.
2639 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2641 MonoTransparentProxy *tproxy;
2642 MonoRemoteClass *remote_class;
2643 gboolean redo_vtable;
2645 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2646 mono_domain_lock (domain);
2648 tproxy = (MonoTransparentProxy*) proxy_object;
2649 remote_class = tproxy->remote_class;
2651 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2654 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2655 if (remote_class->interfaces [i] == klass)
2656 redo_vtable = FALSE;
2659 redo_vtable = (remote_class->proxy_class != klass);
2663 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2664 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2667 mono_domain_unlock (domain);
2668 mono_loader_unlock ();
2673 * mono_object_get_virtual_method:
2674 * @obj: object to operate on.
2677 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2678 * the instance of a callvirt of method.
2681 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2684 MonoMethod **vtable;
2686 MonoMethod *res = NULL;
2688 klass = mono_object_class (obj);
2689 if (klass == mono_defaults.transparent_proxy_class) {
2690 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2696 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2699 mono_class_setup_vtable (klass);
2700 vtable = klass->vtable;
2702 if (method->slot == -1) {
2703 /* method->slot might not be set for instances of generic methods */
2704 if (method->is_inflated) {
2705 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2706 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2709 g_assert_not_reached ();
2713 /* check method->slot is a valid index: perform isinstance? */
2714 if (method->slot != -1) {
2715 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2717 gboolean variance_used = FALSE;
2718 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2719 g_assert (iface_offset > 0);
2720 res = vtable [iface_offset + method->slot];
2723 res = vtable [method->slot];
2728 /* It may be an interface, abstract class method or generic method */
2729 if (!res || mono_method_signature (res)->generic_param_count)
2732 /* generic methods demand invoke_with_check */
2733 if (mono_method_signature (res)->generic_param_count)
2734 res = mono_marshal_get_remoting_invoke_with_check (res);
2737 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2738 res = mono_cominterop_get_invoke (res);
2741 res = mono_marshal_get_remoting_invoke (res);
2744 if (method->is_inflated) {
2745 /* Have to inflate the result */
2746 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2756 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2758 g_error ("runtime invoke called on uninitialized runtime");
2762 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2765 * mono_runtime_invoke:
2766 * @method: method to invoke
2767 * @obJ: object instance
2768 * @params: arguments to the method
2769 * @exc: exception information.
2771 * Invokes the method represented by @method on the object @obj.
2773 * obj is the 'this' pointer, it should be NULL for static
2774 * methods, a MonoObject* for object instances and a pointer to
2775 * the value type for value types.
2777 * The params array contains the arguments to the method with the
2778 * same convention: MonoObject* pointers for object instances and
2779 * pointers to the value type otherwise.
2781 * From unmanaged code you'll usually use the
2782 * mono_runtime_invoke() variant.
2784 * Note that this function doesn't handle virtual methods for
2785 * you, it will exec the exact method you pass: we still need to
2786 * expose a function to lookup the derived class implementation
2787 * of a virtual method (there are examples of this in the code,
2790 * You can pass NULL as the exc argument if you don't want to
2791 * catch exceptions, otherwise, *exc will be set to the exception
2792 * thrown, if any. if an exception is thrown, you can't use the
2793 * MonoObject* result from the function.
2795 * If the method returns a value type, it is boxed in an object
2799 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2803 if (mono_runtime_get_no_exec ())
2804 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2806 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2807 mono_profiler_method_start_invoke (method);
2809 result = default_mono_runtime_invoke (method, obj, params, exc);
2811 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2812 mono_profiler_method_end_invoke (method);
2818 * mono_method_get_unmanaged_thunk:
2819 * @method: method to generate a thunk for.
2821 * Returns an unmanaged->managed thunk that can be used to call
2822 * a managed method directly from C.
2824 * The thunk's C signature closely matches the managed signature:
2826 * C#: public bool Equals (object obj);
2827 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2828 * MonoObject*, MonoException**);
2830 * The 1st ("this") parameter must not be used with static methods:
2832 * C#: public static bool ReferenceEquals (object a, object b);
2833 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2836 * The last argument must be a non-null pointer of a MonoException* pointer.
2837 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2838 * exception has been thrown in managed code. Otherwise it will point
2839 * to the MonoException* caught by the thunk. In this case, the result of
2840 * the thunk is undefined:
2842 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2843 * MonoException *ex = NULL;
2844 * Equals func = mono_method_get_unmanaged_thunk (method);
2845 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2847 * // handle exception
2850 * The calling convention of the thunk matches the platform's default
2851 * convention. This means that under Windows, C declarations must
2852 * contain the __stdcall attribute:
2854 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2855 * MonoObject*, MonoException**);
2859 * Value type arguments and return values are treated as they were objects:
2861 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2862 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2864 * Arguments must be properly boxed upon trunk's invocation, while return
2865 * values must be unboxed.
2868 mono_method_get_unmanaged_thunk (MonoMethod *method)
2870 method = mono_marshal_get_thunk_invoke_wrapper (method);
2871 return mono_compile_method (method);
2875 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2879 /* object fields cannot be byref, so we don't need a
2881 gpointer *p = (gpointer*)dest;
2888 case MONO_TYPE_BOOLEAN:
2890 case MONO_TYPE_U1: {
2891 guint8 *p = (guint8*)dest;
2892 *p = value ? *(guint8*)value : 0;
2897 case MONO_TYPE_CHAR: {
2898 guint16 *p = (guint16*)dest;
2899 *p = value ? *(guint16*)value : 0;
2902 #if SIZEOF_VOID_P == 4
2907 case MONO_TYPE_U4: {
2908 gint32 *p = (gint32*)dest;
2909 *p = value ? *(gint32*)value : 0;
2912 #if SIZEOF_VOID_P == 8
2917 case MONO_TYPE_U8: {
2918 gint64 *p = (gint64*)dest;
2919 *p = value ? *(gint64*)value : 0;
2922 case MONO_TYPE_R4: {
2923 float *p = (float*)dest;
2924 *p = value ? *(float*)value : 0;
2927 case MONO_TYPE_R8: {
2928 double *p = (double*)dest;
2929 *p = value ? *(double*)value : 0;
2932 case MONO_TYPE_STRING:
2933 case MONO_TYPE_SZARRAY:
2934 case MONO_TYPE_CLASS:
2935 case MONO_TYPE_OBJECT:
2936 case MONO_TYPE_ARRAY:
2937 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2939 case MONO_TYPE_FNPTR:
2940 case MONO_TYPE_PTR: {
2941 gpointer *p = (gpointer*)dest;
2942 *p = deref_pointer? *(gpointer*)value: value;
2945 case MONO_TYPE_VALUETYPE:
2946 /* note that 't' and 'type->type' can be different */
2947 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2948 t = mono_class_enum_basetype (type->data.klass)->type;
2951 MonoClass *class = mono_class_from_mono_type (type);
2952 int size = mono_class_value_size (class, NULL);
2954 mono_gc_bzero (dest, size);
2956 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2959 case MONO_TYPE_GENERICINST:
2960 t = type->data.generic_class->container_class->byval_arg.type;
2963 g_error ("got type %x", type->type);
2968 * mono_field_set_value:
2969 * @obj: Instance object
2970 * @field: MonoClassField describing the field to set
2971 * @value: The value to be set
2973 * Sets the value of the field described by @field in the object instance @obj
2974 * to the value passed in @value. This method should only be used for instance
2975 * fields. For static fields, use mono_field_static_set_value.
2977 * The value must be on the native format of the field type.
2980 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2984 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2986 dest = (char*)obj + field->offset;
2987 set_value (field->type, dest, value, FALSE);
2991 * mono_field_static_set_value:
2992 * @field: MonoClassField describing the field to set
2993 * @value: The value to be set
2995 * Sets the value of the static field described by @field
2996 * to the value passed in @value.
2998 * The value must be on the native format of the field type.
3001 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3005 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3006 /* you cant set a constant! */
3007 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3009 if (field->offset == -1) {
3010 /* Special static */
3013 mono_domain_lock (vt->domain);
3014 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3015 mono_domain_unlock (vt->domain);
3016 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3018 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3020 set_value (field->type, dest, value, FALSE);
3024 * mono_vtable_get_static_field_data:
3026 * Internal use function: return a pointer to the memory holding the static fields
3027 * for a class or NULL if there are no static fields.
3028 * This is exported only for use by the debugger.
3031 mono_vtable_get_static_field_data (MonoVTable *vt)
3033 if (!vt->has_static_fields)
3035 return vt->vtable [vt->klass->vtable_size];
3039 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3043 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3044 if (field->offset == -1) {
3045 /* Special static */
3048 mono_domain_lock (vt->domain);
3049 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3050 mono_domain_unlock (vt->domain);
3051 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3053 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3056 src = (guint8*)obj + field->offset;
3063 * mono_field_get_value:
3064 * @obj: Object instance
3065 * @field: MonoClassField describing the field to fetch information from
3066 * @value: pointer to the location where the value will be stored
3068 * Use this routine to get the value of the field @field in the object
3071 * The pointer provided by value must be of the field type, for reference
3072 * types this is a MonoObject*, for value types its the actual pointer to
3077 * mono_field_get_value (obj, int_field, &i);
3080 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3086 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3088 src = (char*)obj + field->offset;
3089 set_value (field->type, value, src, TRUE);
3093 * mono_field_get_value_object:
3094 * @domain: domain where the object will be created (if boxing)
3095 * @field: MonoClassField describing the field to fetch information from
3096 * @obj: The object instance for the field.
3098 * Returns: a new MonoObject with the value from the given field. If the
3099 * field represents a value type, the value is boxed.
3103 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3107 MonoVTable *vtable = NULL;
3109 gboolean is_static = FALSE;
3110 gboolean is_ref = FALSE;
3111 gboolean is_literal = FALSE;
3112 gboolean is_ptr = FALSE;
3114 MonoType *type = mono_field_get_type_checked (field, &error);
3116 if (!mono_error_ok (&error))
3117 mono_error_raise_exception (&error);
3119 switch (type->type) {
3120 case MONO_TYPE_STRING:
3121 case MONO_TYPE_OBJECT:
3122 case MONO_TYPE_CLASS:
3123 case MONO_TYPE_ARRAY:
3124 case MONO_TYPE_SZARRAY:
3129 case MONO_TYPE_BOOLEAN:
3132 case MONO_TYPE_CHAR:
3141 case MONO_TYPE_VALUETYPE:
3142 is_ref = type->byref;
3144 case MONO_TYPE_GENERICINST:
3145 is_ref = !mono_type_generic_inst_is_valuetype (type);
3151 g_error ("type 0x%x not handled in "
3152 "mono_field_get_value_object", type->type);
3156 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3159 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3163 vtable = mono_class_vtable (domain, field->parent);
3165 char *name = mono_type_get_full_name (field->parent);
3166 /*FIXME extend this to use the MonoError api*/
3167 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3171 if (!vtable->initialized)
3172 mono_runtime_class_init (vtable);
3180 get_default_field_value (domain, field, &o);
3181 } else if (is_static) {
3182 mono_field_static_get_value (vtable, field, &o);
3184 mono_field_get_value (obj, field, &o);
3190 static MonoMethod *m;
3196 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3197 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3203 get_default_field_value (domain, field, v);
3204 } else if (is_static) {
3205 mono_field_static_get_value (vtable, field, v);
3207 mono_field_get_value (obj, field, v);
3210 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3212 args [1] = mono_type_get_object (mono_domain_get (), type);
3214 return mono_runtime_invoke (m, NULL, args, NULL);
3217 /* boxed value type */
3218 klass = mono_class_from_mono_type (type);
3220 if (mono_class_is_nullable (klass))
3221 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3223 o = mono_object_new (domain, klass);
3224 v = ((gchar *) o) + sizeof (MonoObject);
3227 get_default_field_value (domain, field, v);
3228 } else if (is_static) {
3229 mono_field_static_get_value (vtable, field, v);
3231 mono_field_get_value (obj, field, v);
3238 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3241 const char *p = blob;
3242 mono_metadata_decode_blob_size (p, &p);
3245 case MONO_TYPE_BOOLEAN:
3248 *(guint8 *) value = *p;
3250 case MONO_TYPE_CHAR:
3253 *(guint16*) value = read16 (p);
3257 *(guint32*) value = read32 (p);
3261 *(guint64*) value = read64 (p);
3264 readr4 (p, (float*) value);
3267 readr8 (p, (double*) value);
3269 case MONO_TYPE_STRING:
3270 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3272 case MONO_TYPE_CLASS:
3273 *(gpointer*) value = NULL;
3277 g_warning ("type 0x%02x should not be in constant table", type);
3283 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3285 MonoTypeEnum def_type;
3288 data = mono_class_get_field_default_value (field, &def_type);
3289 mono_get_constant_value_from_blob (domain, def_type, data, value);
3293 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3297 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3299 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3300 get_default_field_value (vt->domain, field, value);
3304 if (field->offset == -1) {
3305 /* Special static */
3306 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3307 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3309 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3311 set_value (field->type, value, src, TRUE);
3315 * mono_field_static_get_value:
3316 * @vt: vtable to the object
3317 * @field: MonoClassField describing the field to fetch information from
3318 * @value: where the value is returned
3320 * Use this routine to get the value of the static field @field value.
3322 * The pointer provided by value must be of the field type, for reference
3323 * types this is a MonoObject*, for value types its the actual pointer to
3328 * mono_field_static_get_value (vt, int_field, &i);
3331 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3333 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3337 * mono_property_set_value:
3338 * @prop: MonoProperty to set
3339 * @obj: instance object on which to act
3340 * @params: parameters to pass to the propery
3341 * @exc: optional exception
3343 * Invokes the property's set method with the given arguments on the
3344 * object instance obj (or NULL for static properties).
3346 * You can pass NULL as the exc argument if you don't want to
3347 * catch exceptions, otherwise, *exc will be set to the exception
3348 * thrown, if any. if an exception is thrown, you can't use the
3349 * MonoObject* result from the function.
3352 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3354 default_mono_runtime_invoke (prop->set, obj, params, exc);
3358 * mono_property_get_value:
3359 * @prop: MonoProperty to fetch
3360 * @obj: instance object on which to act
3361 * @params: parameters to pass to the propery
3362 * @exc: optional exception
3364 * Invokes the property's get method with the given arguments on the
3365 * object instance obj (or NULL for static properties).
3367 * You can pass NULL as the exc argument if you don't want to
3368 * catch exceptions, otherwise, *exc will be set to the exception
3369 * thrown, if any. if an exception is thrown, you can't use the
3370 * MonoObject* result from the function.
3372 * Returns: the value from invoking the get method on the property.
3375 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3377 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3381 * mono_nullable_init:
3382 * @buf: The nullable structure to initialize.
3383 * @value: the value to initialize from
3384 * @klass: the type for the object
3386 * Initialize the nullable structure pointed to by @buf from @value which
3387 * should be a boxed value type. The size of @buf should be able to hold
3388 * as much data as the @klass->instance_size (which is the number of bytes
3389 * that will be copies).
3391 * Since Nullables have variable structure, we can not define a C
3392 * structure for them.
3395 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3397 MonoClass *param_class = klass->cast_class;
3399 mono_class_setup_fields_locking (klass);
3400 g_assert (klass->fields_inited);
3402 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3403 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3405 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3407 if (param_class->has_references)
3408 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3410 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3412 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3417 * mono_nullable_box:
3418 * @buf: The buffer representing the data to be boxed
3419 * @klass: the type to box it as.
3421 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3425 mono_nullable_box (guint8 *buf, MonoClass *klass)
3427 MonoClass *param_class = klass->cast_class;
3429 mono_class_setup_fields_locking (klass);
3430 g_assert (klass->fields_inited);
3432 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3433 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3435 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3436 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3437 if (param_class->has_references)
3438 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3440 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3448 * mono_get_delegate_invoke:
3449 * @klass: The delegate class
3451 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3454 mono_get_delegate_invoke (MonoClass *klass)
3458 /* This is called at runtime, so avoid the slower search in metadata */
3459 mono_class_setup_methods (klass);
3460 if (klass->exception_type)
3462 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3467 * mono_runtime_delegate_invoke:
3468 * @delegate: pointer to a delegate object.
3469 * @params: parameters for the delegate.
3470 * @exc: Pointer to the exception result.
3472 * Invokes the delegate method @delegate with the parameters provided.
3474 * You can pass NULL as the exc argument if you don't want to
3475 * catch exceptions, otherwise, *exc will be set to the exception
3476 * thrown, if any. if an exception is thrown, you can't use the
3477 * MonoObject* result from the function.
3480 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3483 MonoClass *klass = delegate->vtable->klass;
3485 im = mono_get_delegate_invoke (klass);
3487 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3489 return mono_runtime_invoke (im, delegate, params, exc);
3492 static char **main_args = NULL;
3493 static int num_main_args;
3496 * mono_runtime_get_main_args:
3498 * Returns: a MonoArray with the arguments passed to the main program
3501 mono_runtime_get_main_args (void)
3505 MonoDomain *domain = mono_domain_get ();
3510 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3512 for (i = 0; i < num_main_args; ++i)
3513 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3519 free_main_args (void)
3523 for (i = 0; i < num_main_args; ++i)
3524 g_free (main_args [i]);
3529 * mono_runtime_run_main:
3530 * @method: the method to start the application with (usually Main)
3531 * @argc: number of arguments from the command line
3532 * @argv: array of strings from the command line
3533 * @exc: excetption results
3535 * Execute a standard Main() method (argc/argv contains the
3536 * executable name). This method also sets the command line argument value
3537 * needed by System.Environment.
3542 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3546 MonoArray *args = NULL;
3547 MonoDomain *domain = mono_domain_get ();
3548 gchar *utf8_fullpath;
3549 MonoMethodSignature *sig;
3551 g_assert (method != NULL);
3553 mono_thread_set_main (mono_thread_current ());
3555 main_args = g_new0 (char*, argc);
3556 num_main_args = argc;
3558 if (!g_path_is_absolute (argv [0])) {
3559 gchar *basename = g_path_get_basename (argv [0]);
3560 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3564 utf8_fullpath = mono_utf8_from_external (fullpath);
3565 if(utf8_fullpath == NULL) {
3566 /* Printing the arg text will cause glib to
3567 * whinge about "Invalid UTF-8", but at least
3568 * its relevant, and shows the problem text
3571 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3572 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3579 utf8_fullpath = mono_utf8_from_external (argv[0]);
3580 if(utf8_fullpath == NULL) {
3581 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3582 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3587 main_args [0] = utf8_fullpath;
3589 for (i = 1; i < argc; ++i) {
3592 utf8_arg=mono_utf8_from_external (argv[i]);
3593 if(utf8_arg==NULL) {
3594 /* Ditto the comment about Invalid UTF-8 here */
3595 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3596 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3600 main_args [i] = utf8_arg;
3605 sig = mono_method_signature (method);
3607 g_print ("Unable to load Main method.\n");
3611 if (sig->param_count) {
3612 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3613 for (i = 0; i < argc; ++i) {
3614 /* The encodings should all work, given that
3615 * we've checked all these args for the
3618 gchar *str = mono_utf8_from_external (argv [i]);
3619 MonoString *arg = mono_string_new (domain, str);
3620 mono_array_setref (args, i, arg);
3624 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3627 mono_assembly_set_main (method->klass->image->assembly);
3629 return mono_runtime_exec_main (method, args, exc);
3633 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3635 static MonoMethod *serialize_method;
3640 if (!serialize_method) {
3641 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3642 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3645 if (!serialize_method) {
3650 g_assert (!mono_object_class (obj)->marshalbyref);
3654 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3662 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3664 static MonoMethod *deserialize_method;
3669 if (!deserialize_method) {
3670 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3671 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3673 if (!deserialize_method) {
3680 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3688 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3690 static MonoMethod *get_proxy_method;
3692 MonoDomain *domain = mono_domain_get ();
3693 MonoRealProxy *real_proxy;
3694 MonoReflectionType *reflection_type;
3695 MonoTransparentProxy *transparent_proxy;
3697 if (!get_proxy_method)
3698 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3700 g_assert (obj->vtable->klass->marshalbyref);
3702 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3703 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3705 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3706 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3709 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3713 return (MonoObject*) transparent_proxy;
3717 * mono_object_xdomain_representation
3719 * @target_domain: a domain
3720 * @exc: pointer to a MonoObject*
3722 * Creates a representation of obj in the domain target_domain. This
3723 * is either a copy of obj arrived through via serialization and
3724 * deserialization or a proxy, depending on whether the object is
3725 * serializable or marshal by ref. obj must not be in target_domain.
3727 * If the object cannot be represented in target_domain, NULL is
3728 * returned and *exc is set to an appropriate exception.
3731 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3733 MonoObject *deserialized = NULL;
3734 gboolean failure = FALSE;
3738 if (mono_object_class (obj)->marshalbyref) {
3739 deserialized = make_transparent_proxy (obj, &failure, exc);
3741 MonoDomain *domain = mono_domain_get ();
3742 MonoObject *serialized;
3744 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3745 serialized = serialize_object (obj, &failure, exc);
3746 mono_domain_set_internal_with_options (target_domain, FALSE);
3748 deserialized = deserialize_object (serialized, &failure, exc);
3749 if (domain != target_domain)
3750 mono_domain_set_internal_with_options (domain, FALSE);
3753 return deserialized;
3756 /* Used in call_unhandled_exception_delegate */
3758 create_unhandled_exception_eventargs (MonoObject *exc)
3762 MonoMethod *method = NULL;
3763 MonoBoolean is_terminating = TRUE;
3766 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3769 mono_class_init (klass);
3771 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3772 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3776 args [1] = &is_terminating;
3778 obj = mono_object_new (mono_domain_get (), klass);
3779 mono_runtime_invoke (method, obj, args, NULL);
3784 /* Used in mono_unhandled_exception */
3786 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3787 MonoObject *e = NULL;
3789 MonoDomain *current_domain = mono_domain_get ();
3791 if (domain != current_domain)
3792 mono_domain_set_internal_with_options (domain, FALSE);
3794 g_assert (domain == mono_object_domain (domain->domain));
3796 if (mono_object_domain (exc) != domain) {
3797 MonoObject *serialization_exc;
3799 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3801 if (serialization_exc) {
3803 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3806 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3807 "System.Runtime.Serialization", "SerializationException",
3808 "Could not serialize unhandled exception.");
3812 g_assert (mono_object_domain (exc) == domain);
3814 pa [0] = domain->domain;
3815 pa [1] = create_unhandled_exception_eventargs (exc);
3816 mono_runtime_delegate_invoke (delegate, pa, &e);
3818 if (domain != current_domain)
3819 mono_domain_set_internal_with_options (current_domain, FALSE);
3823 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3824 if (!mono_error_ok (&error)) {
3825 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3826 mono_error_cleanup (&error);
3828 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3834 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3837 * mono_runtime_unhandled_exception_policy_set:
3838 * @policy: the new policy
3840 * This is a VM internal routine.
3842 * Sets the runtime policy for handling unhandled exceptions.
3845 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3846 runtime_unhandled_exception_policy = policy;
3850 * mono_runtime_unhandled_exception_policy_get:
3852 * This is a VM internal routine.
3854 * Gets the runtime policy for handling unhandled exceptions.
3856 MonoRuntimeUnhandledExceptionPolicy
3857 mono_runtime_unhandled_exception_policy_get (void) {
3858 return runtime_unhandled_exception_policy;
3862 * mono_unhandled_exception:
3863 * @exc: exception thrown
3865 * This is a VM internal routine.
3867 * We call this function when we detect an unhandled exception
3868 * in the default domain.
3870 * It invokes the * UnhandledException event in AppDomain or prints
3871 * a warning to the console
3874 mono_unhandled_exception (MonoObject *exc)
3876 MonoDomain *current_domain = mono_domain_get ();
3877 MonoDomain *root_domain = mono_get_root_domain ();
3878 MonoClassField *field;
3879 MonoObject *current_appdomain_delegate;
3880 MonoObject *root_appdomain_delegate;
3882 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3883 "UnhandledException");
3886 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3887 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3888 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3889 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3890 if (current_domain != root_domain) {
3891 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3893 current_appdomain_delegate = NULL;
3896 /* set exitcode only if we will abort the process */
3897 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3899 mono_environment_exitcode_set (1);
3900 mono_print_unhandled_exception (exc);
3902 if (root_appdomain_delegate) {
3903 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3905 if (current_appdomain_delegate) {
3906 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3913 * mono_runtime_exec_managed_code:
3914 * @domain: Application domain
3915 * @main_func: function to invoke from the execution thread
3916 * @main_args: parameter to the main_func
3918 * Launch a new thread to execute a function
3920 * main_func is called back from the thread with main_args as the
3921 * parameter. The callback function is expected to start Main()
3922 * eventually. This function then waits for all managed threads to
3924 * It is not necesseray anymore to execute managed code in a subthread,
3925 * so this function should not be used anymore by default: just
3926 * execute the code and then call mono_thread_manage ().
3929 mono_runtime_exec_managed_code (MonoDomain *domain,
3930 MonoMainThreadFunc main_func,
3933 mono_thread_create (domain, main_func, main_args);
3935 mono_thread_manage ();
3939 * Execute a standard Main() method (args doesn't contain the
3943 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3948 MonoCustomAttrInfo* cinfo;
3949 gboolean has_stathread_attribute;
3950 MonoInternalThread* thread = mono_thread_internal_current ();
3956 domain = mono_object_domain (args);
3957 if (!domain->entry_assembly) {
3959 MonoAssembly *assembly;
3961 assembly = method->klass->image->assembly;
3962 domain->entry_assembly = assembly;
3963 /* Domains created from another domain already have application_base and configuration_file set */
3964 if (domain->setup->application_base == NULL) {
3965 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3968 if (domain->setup->configuration_file == NULL) {
3969 str = g_strconcat (assembly->image->name, ".config", NULL);
3970 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3972 mono_set_private_bin_path_from_config (domain);
3976 cinfo = mono_custom_attrs_from_method (method);
3978 static MonoClass *stathread_attribute = NULL;
3979 if (!stathread_attribute)
3980 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3981 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3983 mono_custom_attrs_free (cinfo);
3985 has_stathread_attribute = FALSE;
3987 if (has_stathread_attribute) {
3988 thread->apartment_state = ThreadApartmentState_STA;
3990 thread->apartment_state = ThreadApartmentState_MTA;
3992 mono_thread_init_apartment_state ();
3994 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3996 /* FIXME: check signature of method */
3997 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3999 res = mono_runtime_invoke (method, NULL, pa, exc);
4001 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4005 mono_environment_exitcode_set (rval);
4007 mono_runtime_invoke (method, NULL, pa, exc);
4011 /* If the return type of Main is void, only
4012 * set the exitcode if an exception was thrown
4013 * (we don't want to blow away an
4014 * explicitly-set exit code)
4017 mono_environment_exitcode_set (rval);
4021 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4027 * mono_install_runtime_invoke:
4028 * @func: Function to install
4030 * This is a VM internal routine
4033 mono_install_runtime_invoke (MonoInvokeFunc func)
4035 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4040 * mono_runtime_invoke_array:
4041 * @method: method to invoke
4042 * @obJ: object instance
4043 * @params: arguments to the method
4044 * @exc: exception information.
4046 * Invokes the method represented by @method on the object @obj.
4048 * obj is the 'this' pointer, it should be NULL for static
4049 * methods, a MonoObject* for object instances and a pointer to
4050 * the value type for value types.
4052 * The params array contains the arguments to the method with the
4053 * same convention: MonoObject* pointers for object instances and
4054 * pointers to the value type otherwise. The _invoke_array
4055 * variant takes a C# object[] as the params argument (MonoArray
4056 * *params): in this case the value types are boxed inside the
4057 * respective reference representation.
4059 * From unmanaged code you'll usually use the
4060 * mono_runtime_invoke() variant.
4062 * Note that this function doesn't handle virtual methods for
4063 * you, it will exec the exact method you pass: we still need to
4064 * expose a function to lookup the derived class implementation
4065 * of a virtual method (there are examples of this in the code,
4068 * You can pass NULL as the exc argument if you don't want to
4069 * catch exceptions, otherwise, *exc will be set to the exception
4070 * thrown, if any. if an exception is thrown, you can't use the
4071 * MonoObject* result from the function.
4073 * If the method returns a value type, it is boxed in an object
4077 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4080 MonoMethodSignature *sig = mono_method_signature (method);
4081 gpointer *pa = NULL;
4084 gboolean has_byref_nullables = FALSE;
4086 if (NULL != params) {
4087 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4088 for (i = 0; i < mono_array_length (params); i++) {
4089 MonoType *t = sig->params [i];
4095 case MONO_TYPE_BOOLEAN:
4098 case MONO_TYPE_CHAR:
4107 case MONO_TYPE_VALUETYPE:
4108 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4109 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4110 pa [i] = mono_array_get (params, MonoObject*, i);
4112 has_byref_nullables = TRUE;
4114 /* MS seems to create the objects if a null is passed in */
4115 if (!mono_array_get (params, MonoObject*, i))
4116 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4120 * We can't pass the unboxed vtype byref to the callee, since
4121 * that would mean the callee would be able to modify boxed
4122 * primitive types. So we (and MS) make a copy of the boxed
4123 * object, pass that to the callee, and replace the original
4124 * boxed object in the arg array with the copy.
4126 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4127 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4128 mono_array_setref (params, i, copy);
4131 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4134 case MONO_TYPE_STRING:
4135 case MONO_TYPE_OBJECT:
4136 case MONO_TYPE_CLASS:
4137 case MONO_TYPE_ARRAY:
4138 case MONO_TYPE_SZARRAY:
4140 pa [i] = mono_array_addr (params, MonoObject*, i);
4141 // FIXME: I need to check this code path
4143 pa [i] = mono_array_get (params, MonoObject*, i);
4145 case MONO_TYPE_GENERICINST:
4147 t = &t->data.generic_class->container_class->this_arg;
4149 t = &t->data.generic_class->container_class->byval_arg;
4151 case MONO_TYPE_PTR: {
4154 /* The argument should be an IntPtr */
4155 arg = mono_array_get (params, MonoObject*, i);
4159 g_assert (arg->vtable->klass == mono_defaults.int_class);
4160 pa [i] = ((MonoIntPtr*)arg)->m_value;
4165 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4170 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4173 if (mono_class_is_nullable (method->klass)) {
4174 /* Need to create a boxed vtype instead */
4180 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4184 obj = mono_object_new (mono_domain_get (), method->klass);
4185 g_assert (obj); /*maybe we should raise a TLE instead?*/
4186 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4187 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4189 if (method->klass->valuetype)
4190 o = mono_object_unbox (obj);
4193 } else if (method->klass->valuetype) {
4194 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4197 mono_runtime_invoke (method, o, pa, exc);
4200 if (mono_class_is_nullable (method->klass)) {
4201 MonoObject *nullable;
4203 /* Convert the unboxed vtype into a Nullable structure */
4204 nullable = mono_object_new (mono_domain_get (), method->klass);
4206 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4207 obj = mono_object_unbox (nullable);
4210 /* obj must be already unboxed if needed */
4211 res = mono_runtime_invoke (method, obj, pa, exc);
4213 if (sig->ret->type == MONO_TYPE_PTR) {
4214 MonoClass *pointer_class;
4215 static MonoMethod *box_method;
4217 MonoObject *box_exc;
4220 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4221 * convert it to a Pointer object.
4223 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4225 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4227 g_assert (res->vtable->klass == mono_defaults.int_class);
4228 box_args [0] = ((MonoIntPtr*)res)->m_value;
4229 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4230 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4231 g_assert (!box_exc);
4234 if (has_byref_nullables) {
4236 * The runtime invoke wrapper already converted byref nullables back,
4237 * and stored them in pa, we just need to copy them back to the
4240 for (i = 0; i < mono_array_length (params); i++) {
4241 MonoType *t = sig->params [i];
4243 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4244 mono_array_setref (params, i, pa [i]);
4253 arith_overflow (void)
4255 mono_raise_exception (mono_get_exception_overflow ());
4259 * mono_object_allocate:
4260 * @size: number of bytes to allocate
4262 * This is a very simplistic routine until we have our GC-aware
4265 * Returns: an allocated object of size @size, or NULL on failure.
4267 static inline void *
4268 mono_object_allocate (size_t size, MonoVTable *vtable)
4271 mono_stats.new_object_count++;
4272 ALLOC_OBJECT (o, vtable, size);
4278 * mono_object_allocate_ptrfree:
4279 * @size: number of bytes to allocate
4281 * Note that the memory allocated is not zeroed.
4282 * Returns: an allocated object of size @size, or NULL on failure.
4284 static inline void *
4285 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4288 mono_stats.new_object_count++;
4289 ALLOC_PTRFREE (o, vtable, size);
4293 static inline void *
4294 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4297 ALLOC_TYPED (o, size, vtable);
4298 mono_stats.new_object_count++;
4305 * @klass: the class of the object that we want to create
4307 * Returns: a newly created object whose definition is
4308 * looked up using @klass. This will not invoke any constructors,
4309 * so the consumer of this routine has to invoke any constructors on
4310 * its own to initialize the object.
4312 * It returns NULL on failure.
4315 mono_object_new (MonoDomain *domain, MonoClass *klass)
4319 MONO_ARCH_SAVE_REGS;
4320 vtable = mono_class_vtable (domain, klass);
4323 return mono_object_new_specific (vtable);
4327 * mono_object_new_pinned:
4329 * Same as mono_object_new, but the returned object will be pinned.
4330 * For SGEN, these objects will only be freed at appdomain unload.
4333 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4337 MONO_ARCH_SAVE_REGS;
4338 vtable = mono_class_vtable (domain, klass);
4343 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4345 return mono_object_new_specific (vtable);
4350 * mono_object_new_specific:
4351 * @vtable: the vtable of the object that we want to create
4353 * Returns: A newly created object with class and domain specified
4357 mono_object_new_specific (MonoVTable *vtable)
4361 MONO_ARCH_SAVE_REGS;
4363 /* check for is_com_object for COM Interop */
4364 if (vtable->remote || vtable->klass->is_com_object)
4367 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4370 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4373 mono_class_init (klass);
4375 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4377 vtable->domain->create_proxy_for_type_method = im;
4380 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4382 o = mono_runtime_invoke (im, NULL, pa, NULL);
4383 if (o != NULL) return o;
4386 return mono_object_new_alloc_specific (vtable);
4390 mono_object_new_alloc_specific (MonoVTable *vtable)
4394 if (!vtable->klass->has_references) {
4395 o = mono_object_new_ptrfree (vtable);
4396 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4397 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4399 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4400 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4402 if (G_UNLIKELY (vtable->klass->has_finalize))
4403 mono_object_register_finalizer (o);
4405 if (G_UNLIKELY (profile_allocs))
4406 mono_profiler_allocation (o, vtable->klass);
4411 mono_object_new_fast (MonoVTable *vtable)
4414 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4419 mono_object_new_ptrfree (MonoVTable *vtable)
4422 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4423 #if NEED_TO_ZERO_PTRFREE
4424 /* an inline memset is much faster for the common vcase of small objects
4425 * note we assume the allocated size is a multiple of sizeof (void*).
4427 if (vtable->klass->instance_size < 128) {
4429 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4430 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4436 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4443 mono_object_new_ptrfree_box (MonoVTable *vtable)
4446 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4447 /* the object will be boxed right away, no need to memzero it */
4452 * mono_class_get_allocation_ftn:
4454 * @for_box: the object will be used for boxing
4455 * @pass_size_in_words:
4457 * Return the allocation function appropriate for the given class.
4461 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4463 *pass_size_in_words = FALSE;
4465 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4466 profile_allocs = FALSE;
4468 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4469 return mono_object_new_specific;
4471 if (!vtable->klass->has_references) {
4472 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4474 return mono_object_new_ptrfree_box;
4475 return mono_object_new_ptrfree;
4478 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4480 return mono_object_new_fast;
4483 * FIXME: This is actually slower than mono_object_new_fast, because
4484 * of the overhead of parameter passing.
4487 *pass_size_in_words = TRUE;
4488 #ifdef GC_REDIRECT_TO_LOCAL
4489 return GC_local_gcj_fast_malloc;
4491 return GC_gcj_fast_malloc;
4496 return mono_object_new_specific;
4500 * mono_object_new_from_token:
4501 * @image: Context where the type_token is hosted
4502 * @token: a token of the type that we want to create
4504 * Returns: A newly created object whose definition is
4505 * looked up using @token in the @image image
4508 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4512 class = mono_class_get (image, token);
4514 return mono_object_new (domain, class);
4519 * mono_object_clone:
4520 * @obj: the object to clone
4522 * Returns: A newly created object who is a shallow copy of @obj
4525 mono_object_clone (MonoObject *obj)
4528 int size = obj->vtable->klass->instance_size;
4530 if (obj->vtable->klass->rank)
4531 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4533 o = mono_object_allocate (size, obj->vtable);
4535 if (obj->vtable->klass->has_references) {
4536 mono_gc_wbarrier_object_copy (o, obj);
4538 int size = obj->vtable->klass->instance_size;
4539 /* do not copy the sync state */
4540 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4542 if (G_UNLIKELY (profile_allocs))
4543 mono_profiler_allocation (o, obj->vtable->klass);
4545 if (obj->vtable->klass->has_finalize)
4546 mono_object_register_finalizer (o);
4551 * mono_array_full_copy:
4552 * @src: source array to copy
4553 * @dest: destination array
4555 * Copies the content of one array to another with exactly the same type and size.
4558 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4561 MonoClass *klass = src->obj.vtable->klass;
4563 MONO_ARCH_SAVE_REGS;
4565 g_assert (klass == dest->obj.vtable->klass);
4567 size = mono_array_length (src);
4568 g_assert (size == mono_array_length (dest));
4569 size *= mono_array_element_size (klass);
4571 if (klass->element_class->valuetype) {
4572 if (klass->element_class->has_references)
4573 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4575 mono_gc_memmove (&dest->vector, &src->vector, size);
4577 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4580 mono_gc_memmove (&dest->vector, &src->vector, size);
4585 * mono_array_clone_in_domain:
4586 * @domain: the domain in which the array will be cloned into
4587 * @array: the array to clone
4589 * This routine returns a copy of the array that is hosted on the
4590 * specified MonoDomain.
4593 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4598 MonoClass *klass = array->obj.vtable->klass;
4600 MONO_ARCH_SAVE_REGS;
4602 if (array->bounds == NULL) {
4603 size = mono_array_length (array);
4604 o = mono_array_new_full (domain, klass, &size, NULL);
4606 size *= mono_array_element_size (klass);
4608 if (klass->element_class->valuetype) {
4609 if (klass->element_class->has_references)
4610 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4612 mono_gc_memmove (&o->vector, &array->vector, size);
4614 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4617 mono_gc_memmove (&o->vector, &array->vector, size);
4622 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4623 size = mono_array_element_size (klass);
4624 for (i = 0; i < klass->rank; ++i) {
4625 sizes [i] = array->bounds [i].length;
4626 size *= array->bounds [i].length;
4627 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4629 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4631 if (klass->element_class->valuetype) {
4632 if (klass->element_class->has_references)
4633 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4635 mono_gc_memmove (&o->vector, &array->vector, size);
4637 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4640 mono_gc_memmove (&o->vector, &array->vector, size);
4648 * @array: the array to clone
4650 * Returns: A newly created array who is a shallow copy of @array
4653 mono_array_clone (MonoArray *array)
4655 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4658 /* helper macros to check for overflow when calculating the size of arrays */
4659 #ifdef MONO_BIG_ARRAYS
4660 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4661 #define MYGUINT_MAX MYGUINT64_MAX
4662 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4663 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4664 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4665 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4666 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4668 #define MYGUINT32_MAX 4294967295U
4669 #define MYGUINT_MAX MYGUINT32_MAX
4670 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4671 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4672 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4673 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4674 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4678 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4682 byte_len = mono_array_element_size (class);
4683 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4686 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4688 byte_len += sizeof (MonoArray);
4696 * mono_array_new_full:
4697 * @domain: domain where the object is created
4698 * @array_class: array class
4699 * @lengths: lengths for each dimension in the array
4700 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4702 * This routine creates a new array objects with the given dimensions,
4703 * lower bounds and type.
4706 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4708 uintptr_t byte_len, len, bounds_size;
4711 MonoArrayBounds *bounds;
4715 if (!array_class->inited)
4716 mono_class_init (array_class);
4720 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4721 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4723 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4727 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4729 for (i = 0; i < array_class->rank; ++i) {
4730 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4732 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4733 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4738 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4739 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4743 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4744 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4745 byte_len = (byte_len + 3) & ~3;
4746 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4747 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4748 byte_len += bounds_size;
4751 * Following three lines almost taken from mono_object_new ():
4752 * they need to be kept in sync.
4754 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4755 #ifndef HAVE_SGEN_GC
4756 if (!array_class->has_references) {
4757 o = mono_object_allocate_ptrfree (byte_len, vtable);
4758 #if NEED_TO_ZERO_PTRFREE
4759 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4761 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4762 o = mono_object_allocate_spec (byte_len, vtable);
4764 o = mono_object_allocate (byte_len, vtable);
4767 array = (MonoArray*)o;
4768 array->max_length = len;
4771 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4772 array->bounds = bounds;
4776 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4778 o = mono_gc_alloc_vector (vtable, byte_len, len);
4779 array = (MonoArray*)o;
4780 mono_stats.new_object_count++;
4782 bounds = array->bounds;
4786 for (i = 0; i < array_class->rank; ++i) {
4787 bounds [i].length = lengths [i];
4789 bounds [i].lower_bound = lower_bounds [i];
4793 if (G_UNLIKELY (profile_allocs))
4794 mono_profiler_allocation (o, array_class);
4801 * @domain: domain where the object is created
4802 * @eclass: element class
4803 * @n: number of array elements
4805 * This routine creates a new szarray with @n elements of type @eclass.
4808 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4812 MONO_ARCH_SAVE_REGS;
4814 ac = mono_array_class_get (eclass, 1);
4817 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4821 * mono_array_new_specific:
4822 * @vtable: a vtable in the appropriate domain for an initialized class
4823 * @n: number of array elements
4825 * This routine is a fast alternative to mono_array_new() for code which
4826 * can be sure about the domain it operates in.
4829 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4835 MONO_ARCH_SAVE_REGS;
4837 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4842 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4843 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4846 #ifndef HAVE_SGEN_GC
4847 if (!vtable->klass->has_references) {
4848 o = mono_object_allocate_ptrfree (byte_len, vtable);
4849 #if NEED_TO_ZERO_PTRFREE
4850 ((MonoArray*)o)->bounds = NULL;
4851 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4853 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4854 o = mono_object_allocate_spec (byte_len, vtable);
4856 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4857 o = mono_object_allocate (byte_len, vtable);
4860 ao = (MonoArray *)o;
4863 o = mono_gc_alloc_vector (vtable, byte_len, n);
4865 mono_stats.new_object_count++;
4868 if (G_UNLIKELY (profile_allocs))
4869 mono_profiler_allocation (o, vtable->klass);
4875 * mono_string_new_utf16:
4876 * @text: a pointer to an utf16 string
4877 * @len: the length of the string
4879 * Returns: A newly created string object which contains @text.
4882 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4886 s = mono_string_new_size (domain, len);
4887 g_assert (s != NULL);
4889 memcpy (mono_string_chars (s), text, len * 2);
4895 * mono_string_new_size:
4896 * @text: a pointer to an utf16 string
4897 * @len: the length of the string
4899 * Returns: A newly created string object of @len
4902 mono_string_new_size (MonoDomain *domain, gint32 len)
4906 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4908 /* overflow ? can't fit it, can't allocate it! */
4910 mono_gc_out_of_memory (-1);
4912 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4915 #ifndef HAVE_SGEN_GC
4916 s = mono_object_allocate_ptrfree (size, vtable);
4920 s = mono_gc_alloc_string (vtable, size, len);
4922 #if NEED_TO_ZERO_PTRFREE
4925 if (G_UNLIKELY (profile_allocs))
4926 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4932 * mono_string_new_len:
4933 * @text: a pointer to an utf8 string
4934 * @length: number of bytes in @text to consider
4936 * Returns: A newly created string object which contains @text.
4939 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4941 GError *error = NULL;
4942 MonoString *o = NULL;
4944 glong items_written;
4946 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4949 o = mono_string_new_utf16 (domain, ut, items_written);
4951 g_error_free (error);
4960 * @text: a pointer to an utf8 string
4962 * Returns: A newly created string object which contains @text.
4965 mono_string_new (MonoDomain *domain, const char *text)
4967 GError *error = NULL;
4968 MonoString *o = NULL;
4970 glong items_written;
4975 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4978 o = mono_string_new_utf16 (domain, ut, items_written);
4980 g_error_free (error);
4983 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4988 MonoString *o = NULL;
4990 if (!g_utf8_validate (text, -1, &end))
4993 len = g_utf8_strlen (text, -1);
4994 o = mono_string_new_size (domain, len);
4995 str = mono_string_chars (o);
4997 while (text < end) {
4998 *str++ = g_utf8_get_char (text);
4999 text = g_utf8_next_char (text);
5006 * mono_string_new_wrapper:
5007 * @text: pointer to utf8 characters.
5009 * Helper function to create a string object from @text in the current domain.
5012 mono_string_new_wrapper (const char *text)
5014 MonoDomain *domain = mono_domain_get ();
5016 MONO_ARCH_SAVE_REGS;
5019 return mono_string_new (domain, text);
5026 * @class: the class of the value
5027 * @value: a pointer to the unboxed data
5029 * Returns: A newly created object which contains @value.
5032 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5038 g_assert (class->valuetype);
5039 if (mono_class_is_nullable (class))
5040 return mono_nullable_box (value, class);
5042 vtable = mono_class_vtable (domain, class);
5045 size = mono_class_instance_size (class);
5046 res = mono_object_new_alloc_specific (vtable);
5047 if (G_UNLIKELY (profile_allocs))
5048 mono_profiler_allocation (res, class);
5050 size = size - sizeof (MonoObject);
5053 g_assert (size == mono_class_value_size (class, NULL));
5054 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5056 #if NO_UNALIGNED_ACCESS
5057 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5061 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5064 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5067 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5070 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5073 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5077 if (class->has_finalize)
5078 mono_object_register_finalizer (res);
5084 * @dest: destination pointer
5085 * @src: source pointer
5086 * @klass: a valuetype class
5088 * Copy a valuetype from @src to @dest. This function must be used
5089 * when @klass contains references fields.
5092 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5094 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5098 * mono_value_copy_array:
5099 * @dest: destination array
5100 * @dest_idx: index in the @dest array
5101 * @src: source pointer
5102 * @count: number of items
5104 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5105 * This function must be used when @klass contains references fields.
5106 * Overlap is handled.
5109 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5111 int size = mono_array_element_size (dest->obj.vtable->klass);
5112 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5113 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5114 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5118 * mono_object_get_domain:
5119 * @obj: object to query
5121 * Returns: the MonoDomain where the object is hosted
5124 mono_object_get_domain (MonoObject *obj)
5126 return mono_object_domain (obj);
5130 * mono_object_get_class:
5131 * @obj: object to query
5133 * Returns: the MonOClass of the object.
5136 mono_object_get_class (MonoObject *obj)
5138 return mono_object_class (obj);
5141 * mono_object_get_size:
5142 * @o: object to query
5144 * Returns: the size, in bytes, of @o
5147 mono_object_get_size (MonoObject* o)
5149 MonoClass* klass = mono_object_class (o);
5150 if (klass == mono_defaults.string_class) {
5151 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5152 } else if (o->vtable->rank) {
5153 MonoArray *array = (MonoArray*)o;
5154 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5155 if (array->bounds) {
5158 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5162 return mono_class_instance_size (klass);
5167 * mono_object_unbox:
5168 * @obj: object to unbox
5170 * Returns: a pointer to the start of the valuetype boxed in this
5173 * This method will assert if the object passed is not a valuetype.
5176 mono_object_unbox (MonoObject *obj)
5178 /* add assert for valuetypes? */
5179 g_assert (obj->vtable->klass->valuetype);
5180 return ((char*)obj) + sizeof (MonoObject);
5184 * mono_object_isinst:
5186 * @klass: a pointer to a class
5188 * Returns: @obj if @obj is derived from @klass
5191 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5194 mono_class_init (klass);
5196 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5197 return mono_object_isinst_mbyref (obj, klass);
5202 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5206 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5215 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5216 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5220 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5221 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5224 MonoClass *oklass = vt->klass;
5225 if (oklass == mono_defaults.transparent_proxy_class)
5226 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5228 mono_class_setup_supertypes (klass);
5229 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5233 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5235 MonoDomain *domain = mono_domain_get ();
5237 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5238 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5239 MonoMethod *im = NULL;
5242 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5243 im = mono_object_get_virtual_method (rp, im);
5246 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5249 res = mono_runtime_invoke (im, rp, pa, NULL);
5251 if (*(MonoBoolean *) mono_object_unbox(res)) {
5252 /* Update the vtable of the remote type, so it can safely cast to this new type */
5253 mono_upgrade_remote_class (domain, obj, klass);
5262 * mono_object_castclass_mbyref:
5264 * @klass: a pointer to a class
5266 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5269 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5271 if (!obj) return NULL;
5272 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5274 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5276 "InvalidCastException"));
5281 MonoDomain *orig_domain;
5287 str_lookup (MonoDomain *domain, gpointer user_data)
5289 LDStrInfo *info = user_data;
5290 if (info->res || domain == info->orig_domain)
5292 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5298 mono_string_get_pinned (MonoString *str)
5302 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5303 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5305 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5306 news->length = mono_string_length (str);
5312 #define mono_string_get_pinned(str) (str)
5316 mono_string_is_interned_lookup (MonoString *str, int insert)
5318 MonoGHashTable *ldstr_table;
5322 domain = ((MonoObject *)str)->vtable->domain;
5323 ldstr_table = domain->ldstr_table;
5325 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5330 str = mono_string_get_pinned (str);
5332 mono_g_hash_table_insert (ldstr_table, str, str);
5336 LDStrInfo ldstr_info;
5337 ldstr_info.orig_domain = domain;
5338 ldstr_info.ins = str;
5339 ldstr_info.res = NULL;
5341 mono_domain_foreach (str_lookup, &ldstr_info);
5342 if (ldstr_info.res) {
5344 * the string was already interned in some other domain:
5345 * intern it in the current one as well.
5347 mono_g_hash_table_insert (ldstr_table, str, str);
5357 * mono_string_is_interned:
5358 * @o: String to probe
5360 * Returns whether the string has been interned.
5363 mono_string_is_interned (MonoString *o)
5365 return mono_string_is_interned_lookup (o, FALSE);
5369 * mono_string_intern:
5370 * @o: String to intern
5372 * Interns the string passed.
5373 * Returns: The interned string.
5376 mono_string_intern (MonoString *str)
5378 return mono_string_is_interned_lookup (str, TRUE);
5383 * @domain: the domain where the string will be used.
5384 * @image: a metadata context
5385 * @idx: index into the user string table.
5387 * Implementation for the ldstr opcode.
5388 * Returns: a loaded string from the @image/@idx combination.
5391 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5393 MONO_ARCH_SAVE_REGS;
5395 if (image->dynamic) {
5396 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5399 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5400 return NULL; /*FIXME we should probably be raising an exception here*/
5401 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5406 * mono_ldstr_metadata_sig
5407 * @domain: the domain for the string
5408 * @sig: the signature of a metadata string
5410 * Returns: a MonoString for a string stored in the metadata
5413 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5415 const char *str = sig;
5416 MonoString *o, *interned;
5419 len2 = mono_metadata_decode_blob_size (str, &str);
5422 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5423 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5426 guint16 *p2 = (guint16*)mono_string_chars (o);
5427 for (i = 0; i < len2; ++i) {
5428 *p2 = GUINT16_FROM_LE (*p2);
5434 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5436 /* o will get garbage collected */
5440 o = mono_string_get_pinned (o);
5442 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5449 * mono_string_to_utf8:
5450 * @s: a System.String
5452 * Returns the UTF8 representation for @s.
5453 * The resulting buffer needs to be freed with mono_free().
5455 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5458 mono_string_to_utf8 (MonoString *s)
5461 char *result = mono_string_to_utf8_checked (s, &error);
5463 if (!mono_error_ok (&error))
5464 mono_error_raise_exception (&error);
5469 * mono_string_to_utf8_checked:
5470 * @s: a System.String
5471 * @error: a MonoError.
5473 * Converts a MonoString to its UTF8 representation. May fail; check
5474 * @error to determine whether the conversion was successful.
5475 * The resulting buffer should be freed with mono_free().
5478 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5482 GError *gerror = NULL;
5484 mono_error_init (error);
5490 return g_strdup ("");
5492 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5494 mono_error_set_argument (error, "string", "%s", gerror->message);
5495 g_error_free (gerror);
5498 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5499 if (s->length > written) {
5500 /* allocate the total length and copy the part of the string that has been converted */
5501 char *as2 = g_malloc0 (s->length);
5502 memcpy (as2, as, written);
5511 * mono_string_to_utf8_ignore:
5514 * Converts a MonoString to its UTF8 representation. Will ignore
5515 * invalid surrogate pairs.
5516 * The resulting buffer should be freed with mono_free().
5520 mono_string_to_utf8_ignore (MonoString *s)
5529 return g_strdup ("");
5531 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5533 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5534 if (s->length > written) {
5535 /* allocate the total length and copy the part of the string that has been converted */
5536 char *as2 = g_malloc0 (s->length);
5537 memcpy (as2, as, written);
5546 * mono_string_to_utf8_image_ignore:
5547 * @s: a System.String
5549 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5552 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5554 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5558 * mono_string_to_utf8_mp_ignore:
5559 * @s: a System.String
5561 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5564 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5566 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5571 * mono_string_to_utf16:
5574 * Return an null-terminated array of the utf-16 chars
5575 * contained in @s. The result must be freed with g_free().
5576 * This is a temporary helper until our string implementation
5577 * is reworked to always include the null terminating char.
5580 mono_string_to_utf16 (MonoString *s)
5587 as = g_malloc ((s->length * 2) + 2);
5588 as [(s->length * 2)] = '\0';
5589 as [(s->length * 2) + 1] = '\0';
5592 return (gunichar2 *)(as);
5595 memcpy (as, mono_string_chars(s), s->length * 2);
5596 return (gunichar2 *)(as);
5600 * mono_string_from_utf16:
5601 * @data: the UTF16 string (LPWSTR) to convert
5603 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5605 * Returns: a MonoString.
5608 mono_string_from_utf16 (gunichar2 *data)
5610 MonoDomain *domain = mono_domain_get ();
5616 while (data [len]) len++;
5618 return mono_string_new_utf16 (domain, data, len);
5623 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5630 r = mono_string_to_utf8_ignore (s);
5632 r = mono_string_to_utf8_checked (s, error);
5633 if (!mono_error_ok (error))
5640 len = strlen (r) + 1;
5642 mp_s = mono_mempool_alloc (mp, len);
5644 mp_s = mono_image_alloc (image, len);
5646 memcpy (mp_s, r, len);
5654 * mono_string_to_utf8_image:
5655 * @s: a System.String
5657 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5660 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5662 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5666 * mono_string_to_utf8_mp:
5667 * @s: a System.String
5669 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5672 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5674 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5678 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5681 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5683 eh_callbacks = *cbs;
5686 MonoRuntimeExceptionHandlingCallbacks *
5687 mono_get_eh_callbacks (void)
5689 return &eh_callbacks;
5693 * mono_raise_exception:
5694 * @ex: exception object
5696 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5699 mono_raise_exception (MonoException *ex)
5702 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5703 * that will cause gcc to omit the function epilog, causing problems when
5704 * the JIT tries to walk the stack, since the return address on the stack
5705 * will point into the next function in the executable, not this one.
5707 eh_callbacks.mono_raise_exception (ex);
5711 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5713 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5717 * mono_wait_handle_new:
5718 * @domain: Domain where the object will be created
5719 * @handle: Handle for the wait handle
5721 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5724 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5726 MonoWaitHandle *res;
5727 gpointer params [1];
5728 static MonoMethod *handle_set;
5730 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5732 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5734 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5736 params [0] = &handle;
5737 mono_runtime_invoke (handle_set, res, params, NULL);
5743 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5745 static MonoClassField *f_os_handle;
5746 static MonoClassField *f_safe_handle;
5748 if (!f_os_handle && !f_safe_handle) {
5749 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5750 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5755 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5759 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5766 mono_runtime_capture_context (MonoDomain *domain)
5768 RuntimeInvokeFunction runtime_invoke;
5770 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5771 MonoMethod *method = mono_get_context_capture_method ();
5772 MonoMethod *wrapper;
5775 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5776 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5777 domain->capture_context_method = mono_compile_method (method);
5780 runtime_invoke = domain->capture_context_runtime_invoke;
5782 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5785 * mono_async_result_new:
5786 * @domain:domain where the object will be created.
5787 * @handle: wait handle.
5788 * @state: state to pass to AsyncResult
5789 * @data: C closure data.
5791 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5792 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5796 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5798 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5799 MonoObject *context = mono_runtime_capture_context (domain);
5800 /* we must capture the execution context from the original thread */
5802 MONO_OBJECT_SETREF (res, execution_context, context);
5803 /* note: result may be null if the flow is suppressed */
5807 MONO_OBJECT_SETREF (res, object_data, object_data);
5808 MONO_OBJECT_SETREF (res, async_state, state);
5810 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5812 res->sync_completed = FALSE;
5813 res->completed = FALSE;
5819 mono_message_init (MonoDomain *domain,
5820 MonoMethodMessage *this,
5821 MonoReflectionMethod *method,
5822 MonoArray *out_args)
5824 static MonoClass *object_array_klass;
5825 static MonoClass *byte_array_klass;
5826 static MonoClass *string_array_klass;
5827 MonoMethodSignature *sig = mono_method_signature (method->method);
5833 if (!object_array_klass) {
5836 klass = mono_array_class_get (mono_defaults.object_class, 1);
5839 mono_memory_barrier ();
5840 object_array_klass = klass;
5842 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5845 mono_memory_barrier ();
5846 byte_array_klass = klass;
5848 klass = mono_array_class_get (mono_defaults.string_class, 1);
5851 mono_memory_barrier ();
5852 string_array_klass = klass;
5855 MONO_OBJECT_SETREF (this, method, method);
5857 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5858 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5859 this->async_result = NULL;
5860 this->call_type = CallType_Sync;
5862 names = g_new (char *, sig->param_count);
5863 mono_method_get_param_names (method->method, (const char **) names);
5864 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5866 for (i = 0; i < sig->param_count; i++) {
5867 name = mono_string_new (domain, names [i]);
5868 mono_array_setref (this->names, i, name);
5872 for (i = 0, j = 0; i < sig->param_count; i++) {
5873 if (sig->params [i]->byref) {
5875 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5876 mono_array_setref (this->args, i, arg);
5880 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5884 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5887 mono_array_set (this->arg_types, guint8, i, arg_type);
5892 * mono_remoting_invoke:
5893 * @real_proxy: pointer to a RealProxy object
5894 * @msg: The MonoMethodMessage to execute
5895 * @exc: used to store exceptions
5896 * @out_args: used to store output arguments
5898 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5899 * IMessage interface and it is not trivial to extract results from there. So
5900 * we call an helper method PrivateInvoke instead of calling
5901 * RealProxy::Invoke() directly.
5903 * Returns: the result object.
5906 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5907 MonoObject **exc, MonoArray **out_args)
5909 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5912 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5915 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5917 real_proxy->vtable->domain->private_invoke_method = im;
5920 pa [0] = real_proxy;
5925 return mono_runtime_invoke (im, NULL, pa, exc);
5929 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5930 MonoObject **exc, MonoArray **out_args)
5932 static MonoClass *object_array_klass;
5935 MonoMethodSignature *sig;
5937 int i, j, outarg_count = 0;
5939 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5941 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5942 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5943 target = tp->rp->unwrapped_server;
5945 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5949 domain = mono_domain_get ();
5950 method = msg->method->method;
5951 sig = mono_method_signature (method);
5953 for (i = 0; i < sig->param_count; i++) {
5954 if (sig->params [i]->byref)
5958 if (!object_array_klass) {
5961 klass = mono_array_class_get (mono_defaults.object_class, 1);
5964 mono_memory_barrier ();
5965 object_array_klass = klass;
5968 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5969 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5972 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5974 for (i = 0, j = 0; i < sig->param_count; i++) {
5975 if (sig->params [i]->byref) {
5977 arg = mono_array_get (msg->args, gpointer, i);
5978 mono_array_setref (*out_args, j, arg);
5987 * mono_object_to_string:
5989 * @exc: Any exception thrown by ToString (). May be NULL.
5991 * Returns: the result of calling ToString () on an object.
5994 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5996 static MonoMethod *to_string = NULL;
6002 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6004 method = mono_object_get_virtual_method (obj, to_string);
6006 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
6010 * mono_print_unhandled_exception:
6011 * @exc: The exception
6013 * Prints the unhandled exception.
6016 mono_print_unhandled_exception (MonoObject *exc)
6019 char *message = (char*)"";
6020 gboolean free_message = FALSE;
6023 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6024 message = g_strdup ("OutOfMemoryException");
6026 str = mono_object_to_string (exc, NULL);
6028 message = mono_string_to_utf8_checked (str, &error);
6029 if (!mono_error_ok (&error)) {
6030 mono_error_cleanup (&error);
6031 message = (char *) "";
6033 free_message = TRUE;
6039 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6040 * exc->vtable->klass->name, message);
6042 g_printerr ("\nUnhandled Exception: %s\n", message);
6049 * mono_delegate_ctor:
6050 * @this: pointer to an uninitialized delegate object
6051 * @target: target object
6052 * @addr: pointer to native code
6055 * Initialize a delegate and sets a specific method, not the one
6056 * associated with addr. This is useful when sharing generic code.
6057 * In that case addr will most probably not be associated with the
6058 * correct instantiation of the method.
6061 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6063 MonoDelegate *delegate = (MonoDelegate *)this;
6070 delegate->method = method;
6072 class = this->vtable->klass;
6073 mono_stats.delegate_creations++;
6075 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6077 method = mono_marshal_get_remoting_invoke (method);
6078 delegate->method_ptr = mono_compile_method (method);
6079 MONO_OBJECT_SETREF (delegate, target, target);
6080 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6081 method = mono_marshal_get_unbox_wrapper (method);
6082 delegate->method_ptr = mono_compile_method (method);
6083 MONO_OBJECT_SETREF (delegate, target, target);
6085 delegate->method_ptr = addr;
6086 MONO_OBJECT_SETREF (delegate, target, target);
6089 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6093 * mono_delegate_ctor:
6094 * @this: pointer to an uninitialized delegate object
6095 * @target: target object
6096 * @addr: pointer to native code
6098 * This is used to initialize a delegate.
6101 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6103 MonoDomain *domain = mono_domain_get ();
6105 MonoMethod *method = NULL;
6109 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6111 if (!ji && domain != mono_get_root_domain ())
6112 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6114 method = ji->method;
6115 g_assert (!method->klass->generic_container);
6118 mono_delegate_ctor_with_method (this, target, addr, method);
6122 * mono_method_call_message_new:
6123 * @method: method to encapsulate
6124 * @params: parameters to the method
6125 * @invoke: optional, delegate invoke.
6126 * @cb: async callback delegate.
6127 * @state: state passed to the async callback.
6129 * Translates arguments pointers into a MonoMethodMessage.
6132 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6133 MonoDelegate **cb, MonoObject **state)
6135 MonoDomain *domain = mono_domain_get ();
6136 MonoMethodSignature *sig = mono_method_signature (method);
6137 MonoMethodMessage *msg;
6140 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6143 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6144 count = sig->param_count - 2;
6146 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6147 count = sig->param_count;
6150 for (i = 0; i < count; i++) {
6155 if (sig->params [i]->byref)
6156 vpos = *((gpointer *)params [i]);
6160 type = sig->params [i]->type;
6161 class = mono_class_from_mono_type (sig->params [i]);
6163 if (class->valuetype)
6164 arg = mono_value_box (domain, class, vpos);
6166 arg = *((MonoObject **)vpos);
6168 mono_array_setref (msg->args, i, arg);
6171 if (cb != NULL && state != NULL) {
6172 *cb = *((MonoDelegate **)params [i]);
6174 *state = *((MonoObject **)params [i]);
6181 * mono_method_return_message_restore:
6183 * Restore results from message based processing back to arguments pointers
6186 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6188 MonoMethodSignature *sig = mono_method_signature (method);
6189 int i, j, type, size, out_len;
6191 if (out_args == NULL)
6193 out_len = mono_array_length (out_args);
6197 for (i = 0, j = 0; i < sig->param_count; i++) {
6198 MonoType *pt = sig->params [i];
6203 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6205 arg = mono_array_get (out_args, gpointer, j);
6208 g_assert (type != MONO_TYPE_VOID);
6210 if (MONO_TYPE_IS_REFERENCE (pt)) {
6211 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6214 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6215 size = mono_class_value_size (class, NULL);
6216 if (class->has_references)
6217 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6219 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6221 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6222 mono_gc_bzero (*((gpointer *)params [i]), size);
6232 * mono_load_remote_field:
6233 * @this: pointer to an object
6234 * @klass: klass of the object containing @field
6235 * @field: the field to load
6236 * @res: a storage to store the result
6238 * This method is called by the runtime on attempts to load fields of
6239 * transparent proxy objects. @this points to such TP, @klass is the class of
6240 * the object containing @field. @res is a storage location which can be
6241 * used to store the result.
6243 * Returns: an address pointing to the value of field.
6246 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6248 static MonoMethod *getter = NULL;
6249 MonoDomain *domain = mono_domain_get ();
6250 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6251 MonoClass *field_class;
6252 MonoMethodMessage *msg;
6253 MonoArray *out_args;
6257 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6258 g_assert (res != NULL);
6260 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6261 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6266 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6270 field_class = mono_class_from_mono_type (field->type);
6272 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6273 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6274 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6276 full_name = mono_type_get_full_name (klass);
6277 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6278 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6281 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6283 if (exc) mono_raise_exception ((MonoException *)exc);
6285 if (mono_array_length (out_args) == 0)
6288 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6290 if (field_class->valuetype) {
6291 return ((char *)*res) + sizeof (MonoObject);
6297 * mono_load_remote_field_new:
6302 * Missing documentation.
6305 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6307 static MonoMethod *getter = NULL;
6308 MonoDomain *domain = mono_domain_get ();
6309 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6310 MonoClass *field_class;
6311 MonoMethodMessage *msg;
6312 MonoArray *out_args;
6313 MonoObject *exc, *res;
6316 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6318 field_class = mono_class_from_mono_type (field->type);
6320 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6322 if (field_class->valuetype) {
6323 res = mono_object_new (domain, field_class);
6324 val = ((gchar *) res) + sizeof (MonoObject);
6328 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6333 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6337 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6338 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6340 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6342 full_name = mono_type_get_full_name (klass);
6343 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6344 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6347 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6349 if (exc) mono_raise_exception ((MonoException *)exc);
6351 if (mono_array_length (out_args) == 0)
6354 res = mono_array_get (out_args, MonoObject *, 0);
6360 * mono_store_remote_field:
6361 * @this: pointer to an object
6362 * @klass: klass of the object containing @field
6363 * @field: the field to load
6364 * @val: the value/object to store
6366 * This method is called by the runtime on attempts to store fields of
6367 * transparent proxy objects. @this points to such TP, @klass is the class of
6368 * the object containing @field. @val is the new value to store in @field.
6371 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6373 static MonoMethod *setter = NULL;
6374 MonoDomain *domain = mono_domain_get ();
6375 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6376 MonoClass *field_class;
6377 MonoMethodMessage *msg;
6378 MonoArray *out_args;
6383 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6385 field_class = mono_class_from_mono_type (field->type);
6387 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6388 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6389 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6394 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6398 if (field_class->valuetype)
6399 arg = mono_value_box (domain, field_class, val);
6401 arg = *((MonoObject **)val);
6404 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6405 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6407 full_name = mono_type_get_full_name (klass);
6408 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6409 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6410 mono_array_setref (msg->args, 2, arg);
6413 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6415 if (exc) mono_raise_exception ((MonoException *)exc);
6419 * mono_store_remote_field_new:
6425 * Missing documentation
6428 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6430 static MonoMethod *setter = NULL;
6431 MonoDomain *domain = mono_domain_get ();
6432 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6433 MonoClass *field_class;
6434 MonoMethodMessage *msg;
6435 MonoArray *out_args;
6439 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6441 field_class = mono_class_from_mono_type (field->type);
6443 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6444 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6445 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6450 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6454 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6455 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6457 full_name = mono_type_get_full_name (klass);
6458 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6459 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6460 mono_array_setref (msg->args, 2, arg);
6463 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6465 if (exc) mono_raise_exception ((MonoException *)exc);
6469 * mono_create_ftnptr:
6471 * Given a function address, create a function descriptor for it.
6472 * This is only needed on some platforms.
6475 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6477 return callbacks.create_ftnptr (domain, addr);
6481 * mono_get_addr_from_ftnptr:
6483 * Given a pointer to a function descriptor, return the function address.
6484 * This is only needed on some platforms.
6487 mono_get_addr_from_ftnptr (gpointer descr)
6489 return callbacks.get_addr_from_ftnptr (descr);
6493 * mono_string_chars:
6496 * Returns a pointer to the UCS16 characters stored in the MonoString
6499 mono_string_chars (MonoString *s)
6505 * mono_string_length:
6508 * Returns the lenght in characters of the string
6511 mono_string_length (MonoString *s)
6517 * mono_array_length:
6518 * @array: a MonoArray*
6520 * Returns the total number of elements in the array. This works for
6521 * both vectors and multidimensional arrays.
6524 mono_array_length (MonoArray *array)
6526 return array->max_length;
6530 * mono_array_addr_with_size:
6531 * @array: a MonoArray*
6532 * @size: size of the array elements
6533 * @idx: index into the array
6535 * Returns the address of the @idx element in the array.
6538 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6540 return ((char*)(array)->vector) + size * idx;