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 <mono/utils/mono-memory-model.h>
47 #include "cominterop.h"
50 #define NEED_TO_ZERO_PTRFREE 1
51 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
52 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
53 #ifdef HAVE_GC_GCJ_MALLOC
54 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
62 #define GC_NO_DESCRIPTOR (NULL)
63 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
65 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
67 #define NEED_TO_ZERO_PTRFREE 1
68 #define GC_NO_DESCRIPTOR (NULL)
69 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
70 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
71 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
75 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
76 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
79 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
82 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
85 free_main_args (void);
88 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
91 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
92 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
93 static mono_mutex_t ldstr_section;
95 static gboolean profile_allocs = TRUE;
98 mono_runtime_object_init (MonoObject *this)
100 MonoMethod *method = NULL;
101 MonoClass *klass = this->vtable->klass;
103 method = mono_class_get_method_from_name (klass, ".ctor", 0);
105 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
107 if (method->klass->valuetype)
108 this = mono_object_unbox (this);
109 mono_runtime_invoke (method, this, NULL, NULL);
112 /* The pseudo algorithm for type initialization from the spec
113 Note it doesn't say anything about domains - only threads.
115 2. If the type is initialized you are done.
116 2.1. If the type is not yet initialized, try to take an
118 2.2. If successful, record this thread as responsible for
119 initializing the type and proceed to step 2.3.
120 2.2.1. If not, see whether this thread or any thread
121 waiting for this thread to complete already holds the lock.
122 2.2.2. If so, return since blocking would create a deadlock. This thread
123 will now see an incompletely initialized state for the type,
124 but no deadlock will arise.
125 2.2.3 If not, block until the type is initialized then return.
126 2.3 Initialize the parent type and then all interfaces implemented
128 2.4 Execute the type initialization code for this type.
129 2.5 Mark the type as initialized, release the initialization lock,
130 awaken any threads waiting for this type to be initialized,
137 guint32 initializing_tid;
138 guint32 waiting_count;
140 mono_mutex_t initialization_section;
141 } TypeInitializationLock;
143 /* for locking access to type_initialization_hash and blocked_thread_hash */
144 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
145 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
146 static mono_mutex_t type_initialization_section;
148 /* from vtable to lock */
149 static GHashTable *type_initialization_hash;
151 /* from thread id to thread id being waited on */
152 static GHashTable *blocked_thread_hash;
155 static MonoThread *main_thread;
157 /* Functions supplied by the runtime */
158 static MonoRuntimeCallbacks callbacks;
161 * mono_thread_set_main:
162 * @thread: thread to set as the main thread
164 * This function can be used to instruct the runtime to treat @thread
165 * as the main thread, ie, the thread that would normally execute the Main()
166 * method. This basically means that at the end of @thread, the runtime will
167 * wait for the existing foreground threads to quit and other such details.
170 mono_thread_set_main (MonoThread *thread)
172 static gboolean registered = FALSE;
175 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
179 main_thread = thread;
183 mono_thread_get_main (void)
189 mono_type_initialization_init (void)
191 mono_mutex_init_recursive (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 mono_mutex_init_recursive (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 mono_mutex_destroy (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 mono_mutex_destroy (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MonoDomain *domain = vtable->domain;
224 MonoClass *klass = vtable->klass;
228 if (!vtable->init_failed)
229 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
232 * If the initializing thread was rudely aborted, the exception is not stored
236 mono_domain_lock (domain);
237 if (domain->type_init_exception_hash)
238 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
239 mono_domain_unlock (domain);
242 if (klass->name_space && *klass->name_space)
243 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
245 full_name = g_strdup (klass->name);
246 ex = mono_get_exception_type_initialization (full_name, NULL);
253 * mono_runtime_class_init:
254 * @vtable: vtable that needs to be initialized
256 * This routine calls the class constructor for @vtable.
259 mono_runtime_class_init (MonoVTable *vtable)
261 mono_runtime_class_init_full (vtable, TRUE);
265 * mono_runtime_class_init_full:
266 * @vtable that neeeds to be initialized
267 * @raise_exception is TRUE, exceptions are raised intead of returned
271 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
274 MonoException *exc_to_throw;
275 MonoMethod *method = NULL;
281 if (vtable->initialized)
285 klass = vtable->klass;
287 if (!klass->image->checked_module_cctor) {
288 mono_image_check_for_module_cctor (klass->image);
289 if (klass->image->has_module_cctor) {
290 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
291 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
294 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
299 method = mono_class_get_cctor (klass);
302 MonoDomain *domain = vtable->domain;
303 TypeInitializationLock *lock;
304 guint32 tid = GetCurrentThreadId();
305 int do_initialization = 0;
306 MonoDomain *last_domain = NULL;
308 mono_type_initialization_lock ();
309 /* double check... */
310 if (vtable->initialized) {
311 mono_type_initialization_unlock ();
314 if (vtable->init_failed) {
315 mono_type_initialization_unlock ();
317 /* The type initialization already failed once, rethrow the same exception */
319 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
320 return get_type_init_exception_for_vtable (vtable);
322 lock = g_hash_table_lookup (type_initialization_hash, vtable);
324 /* This thread will get to do the initialization */
325 if (mono_domain_get () != domain) {
326 /* Transfer into the target domain */
327 last_domain = mono_domain_get ();
328 if (!mono_domain_set (domain, FALSE)) {
329 vtable->initialized = 1;
330 mono_type_initialization_unlock ();
332 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
333 return mono_get_exception_appdomain_unloaded ();
336 lock = g_malloc (sizeof(TypeInitializationLock));
337 mono_mutex_init_recursive (&lock->initialization_section);
338 lock->initializing_tid = tid;
339 lock->waiting_count = 1;
341 /* grab the vtable lock while this thread still owns type_initialization_section */
342 mono_mutex_lock (&lock->initialization_section);
343 g_hash_table_insert (type_initialization_hash, vtable, lock);
344 do_initialization = 1;
347 TypeInitializationLock *pending_lock;
349 if (lock->initializing_tid == tid || lock->done) {
350 mono_type_initialization_unlock ();
353 /* see if the thread doing the initialization is already blocked on this thread */
354 blocked = GUINT_TO_POINTER (lock->initializing_tid);
355 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
356 if (pending_lock->initializing_tid == tid) {
357 if (!pending_lock->done) {
358 mono_type_initialization_unlock ();
361 /* the thread doing the initialization is blocked on this thread,
362 but on a lock that has already been freed. It just hasn't got
367 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
369 ++lock->waiting_count;
370 /* record the fact that we are waiting on the initializing thread */
371 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
373 mono_type_initialization_unlock ();
375 if (do_initialization) {
376 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
378 /* If the initialization failed, mark the class as unusable. */
379 /* Avoid infinite loops */
381 (klass->image == mono_defaults.corlib &&
382 !strcmp (klass->name_space, "System") &&
383 !strcmp (klass->name, "TypeInitializationException")))) {
384 vtable->init_failed = 1;
386 if (klass->name_space && *klass->name_space)
387 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
389 full_name = g_strdup (klass->name);
390 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
394 * Store the exception object so it could be thrown on subsequent
397 mono_domain_lock (domain);
398 if (!domain->type_init_exception_hash)
399 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
400 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
401 mono_domain_unlock (domain);
405 mono_domain_set (last_domain, TRUE);
407 mono_mutex_unlock (&lock->initialization_section);
409 /* this just blocks until the initializing thread is done */
410 mono_mutex_lock (&lock->initialization_section);
411 mono_mutex_unlock (&lock->initialization_section);
414 mono_type_initialization_lock ();
415 if (lock->initializing_tid != tid)
416 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
417 --lock->waiting_count;
418 if (lock->waiting_count == 0) {
419 mono_mutex_destroy (&lock->initialization_section);
420 g_hash_table_remove (type_initialization_hash, vtable);
423 mono_memory_barrier ();
424 if (!vtable->init_failed)
425 vtable->initialized = 1;
426 mono_type_initialization_unlock ();
428 if (vtable->init_failed) {
429 /* Either we were the initializing thread or we waited for the initialization */
431 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
432 return get_type_init_exception_for_vtable (vtable);
435 vtable->initialized = 1;
442 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
444 MonoVTable *vtable = (MonoVTable*)key;
446 TypeInitializationLock *lock = (TypeInitializationLock*) value;
447 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
450 * Have to set this since it cannot be set by the normal code in
451 * mono_runtime_class_init (). In this case, the exception object is not stored,
452 * and get_type_init_exception_for_class () needs to be aware of this.
454 vtable->init_failed = 1;
455 mono_mutex_unlock (&lock->initialization_section);
456 --lock->waiting_count;
457 if (lock->waiting_count == 0) {
458 mono_mutex_destroy (&lock->initialization_section);
467 mono_release_type_locks (MonoInternalThread *thread)
469 mono_type_initialization_lock ();
470 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
471 mono_type_initialization_unlock ();
475 default_trampoline (MonoMethod *method)
481 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
483 g_assert_not_reached ();
488 #ifndef DISABLE_REMOTING
491 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
493 g_error ("remoting not installed");
497 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
501 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
503 g_assert_not_reached ();
507 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
508 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
509 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
510 static MonoImtThunkBuilder imt_thunk_builder = NULL;
511 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
512 #if (MONO_IMT_SIZE > 32)
513 #error "MONO_IMT_SIZE cannot be larger than 32"
517 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
519 memcpy (&callbacks, cbs, sizeof (*cbs));
522 MonoRuntimeCallbacks*
523 mono_get_runtime_callbacks (void)
529 mono_install_trampoline (MonoTrampoline func)
531 arch_create_jit_trampoline = func? func: default_trampoline;
535 mono_install_jump_trampoline (MonoJumpTrampoline func)
537 arch_create_jump_trampoline = func? func: default_jump_trampoline;
540 #ifndef DISABLE_REMOTING
542 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
544 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
549 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
551 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
555 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
556 imt_thunk_builder = func;
559 static MonoCompileFunc default_mono_compile_method = NULL;
562 * mono_install_compile_method:
563 * @func: function to install
565 * This is a VM internal routine
568 mono_install_compile_method (MonoCompileFunc func)
570 default_mono_compile_method = func;
574 * mono_compile_method:
575 * @method: The method to compile.
577 * This JIT-compiles the method, and returns the pointer to the native code
581 mono_compile_method (MonoMethod *method)
583 if (!default_mono_compile_method) {
584 g_error ("compile method called on uninitialized runtime");
587 return default_mono_compile_method (method);
591 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
593 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
597 mono_runtime_create_delegate_trampoline (MonoClass *klass)
599 return arch_create_delegate_trampoline (mono_domain_get (), klass);
602 static MonoFreeMethodFunc default_mono_free_method = NULL;
605 * mono_install_free_method:
606 * @func: pointer to the MonoFreeMethodFunc used to release a method
608 * This is an internal VM routine, it is used for the engines to
609 * register a handler to release the resources associated with a method.
611 * Methods are freed when no more references to the delegate that holds
615 mono_install_free_method (MonoFreeMethodFunc func)
617 default_mono_free_method = func;
621 * mono_runtime_free_method:
622 * @domain; domain where the method is hosted
623 * @method: method to release
625 * This routine is invoked to free the resources associated with
626 * a method that has been JIT compiled. This is used to discard
627 * methods that were used only temporarily (for example, used in marshalling)
631 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
633 if (default_mono_free_method != NULL)
634 default_mono_free_method (domain, method);
636 mono_method_clear_object (domain, method);
638 mono_free_method (method);
642 * The vtables in the root appdomain are assumed to be reachable by other
643 * roots, and we don't use typed allocation in the other domains.
646 /* The sync block is no longer a GC pointer */
647 #define GC_HEADER_BITMAP (0)
649 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
652 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
654 MonoClassField *field;
660 max_size = mono_class_data_size (class) / sizeof (gpointer);
662 max_size = class->instance_size / sizeof (gpointer);
663 if (max_size > size) {
664 g_assert (offset <= 0);
665 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
670 /*An Ephemeron cannot be marked by sgen*/
671 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
673 memset (bitmap, 0, size / 8);
678 for (p = class; p != NULL; p = p->parent) {
679 gpointer iter = NULL;
680 while ((field = mono_class_get_fields (p, &iter))) {
684 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
686 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
689 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
692 /* FIXME: should not happen, flag as type load error */
693 if (field->type->byref)
696 if (static_fields && field->offset == -1)
700 pos = field->offset / sizeof (gpointer);
703 type = mono_type_get_underlying_type (field->type);
704 switch (type->type) {
707 case MONO_TYPE_FNPTR:
709 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
714 if (class->image != mono_defaults.corlib)
717 case MONO_TYPE_STRING:
718 case MONO_TYPE_SZARRAY:
719 case MONO_TYPE_CLASS:
720 case MONO_TYPE_OBJECT:
721 case MONO_TYPE_ARRAY:
722 g_assert ((field->offset % sizeof(gpointer)) == 0);
724 g_assert (pos < size || pos <= max_size);
725 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
726 *max_set = MAX (*max_set, pos);
728 case MONO_TYPE_GENERICINST:
729 if (!mono_type_generic_inst_is_valuetype (type)) {
730 g_assert ((field->offset % sizeof(gpointer)) == 0);
732 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
733 *max_set = MAX (*max_set, pos);
738 case MONO_TYPE_VALUETYPE: {
739 MonoClass *fclass = mono_class_from_mono_type (field->type);
740 if (fclass->has_references) {
741 /* remove the object header */
742 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
756 case MONO_TYPE_BOOLEAN:
760 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
771 * mono_class_compute_bitmap:
773 * Mono internal function to compute a bitmap of reference fields in a class.
776 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
778 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
783 * similar to the above, but sets the bits in the bitmap for any non-ref field
784 * and ignores static fields
787 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
789 MonoClassField *field;
794 max_size = class->instance_size / sizeof (gpointer);
795 if (max_size >= size) {
796 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
799 for (p = class; p != NULL; p = p->parent) {
800 gpointer iter = NULL;
801 while ((field = mono_class_get_fields (p, &iter))) {
804 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
806 /* FIXME: should not happen, flag as type load error */
807 if (field->type->byref)
810 pos = field->offset / sizeof (gpointer);
813 type = mono_type_get_underlying_type (field->type);
814 switch (type->type) {
815 #if SIZEOF_VOID_P == 8
819 case MONO_TYPE_FNPTR:
824 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
825 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
826 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
829 #if SIZEOF_VOID_P == 4
833 case MONO_TYPE_FNPTR:
838 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
839 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
840 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
846 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
847 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
848 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
851 case MONO_TYPE_BOOLEAN:
854 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
856 case MONO_TYPE_STRING:
857 case MONO_TYPE_SZARRAY:
858 case MONO_TYPE_CLASS:
859 case MONO_TYPE_OBJECT:
860 case MONO_TYPE_ARRAY:
862 case MONO_TYPE_GENERICINST:
863 if (!mono_type_generic_inst_is_valuetype (type)) {
868 case MONO_TYPE_VALUETYPE: {
869 MonoClass *fclass = mono_class_from_mono_type (field->type);
870 /* remove the object header */
871 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
875 g_assert_not_reached ();
884 * mono_class_insecure_overlapping:
885 * check if a class with explicit layout has references and non-references
886 * fields overlapping.
888 * Returns: TRUE if it is insecure to load the type.
891 mono_class_insecure_overlapping (MonoClass *klass)
895 gsize default_bitmap [4] = {0};
897 gsize default_nrbitmap [4] = {0};
898 int i, insecure = FALSE;
901 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
902 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
904 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
905 int idx = i % (sizeof (bitmap [0]) * 8);
906 if (bitmap [idx] & nrbitmap [idx]) {
911 if (bitmap != default_bitmap)
913 if (nrbitmap != default_nrbitmap)
916 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
924 mono_string_alloc (int length)
926 return mono_string_new_size (mono_domain_get (), length);
930 mono_class_compute_gc_descriptor (MonoClass *class)
934 gsize default_bitmap [4] = {0};
935 static gboolean gcj_inited = FALSE;
940 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
941 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
942 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
943 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
945 #ifdef HAVE_GC_GCJ_MALLOC
947 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
951 #ifdef GC_REDIRECT_TO_LOCAL
952 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
953 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
955 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
956 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
961 mono_loader_unlock ();
965 mono_class_init (class);
967 if (class->gc_descr_inited)
970 class->gc_descr_inited = TRUE;
971 class->gc_descr = GC_NO_DESCRIPTOR;
973 bitmap = default_bitmap;
974 if (class == mono_defaults.string_class) {
975 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
976 } else if (class->rank) {
977 mono_class_compute_gc_descriptor (class->element_class);
978 if (!class->element_class->valuetype) {
980 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
981 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
982 class->name_space, class->name);*/
984 /* remove the object header */
985 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
986 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));
987 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
988 class->name_space, class->name);*/
989 if (bitmap != default_bitmap)
993 /*static int count = 0;
996 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
997 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
999 if (class->gc_descr == GC_NO_DESCRIPTOR)
1000 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1002 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1003 if (bitmap != default_bitmap)
1009 * field_is_special_static:
1010 * @fklass: The MonoClass to look up.
1011 * @field: The MonoClassField describing the field.
1013 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1014 * SPECIAL_STATIC_NONE otherwise.
1017 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1019 MonoCustomAttrInfo *ainfo;
1021 ainfo = mono_custom_attrs_from_field (fklass, field);
1024 for (i = 0; i < ainfo->num_attrs; ++i) {
1025 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1026 if (klass->image == mono_defaults.corlib) {
1027 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1028 mono_custom_attrs_free (ainfo);
1029 return SPECIAL_STATIC_THREAD;
1031 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1032 mono_custom_attrs_free (ainfo);
1033 return SPECIAL_STATIC_CONTEXT;
1037 mono_custom_attrs_free (ainfo);
1038 return SPECIAL_STATIC_NONE;
1041 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1042 #define mix(a,b,c) { \
1043 a -= c; a ^= rot(c, 4); c += b; \
1044 b -= a; b ^= rot(a, 6); a += c; \
1045 c -= b; c ^= rot(b, 8); b += a; \
1046 a -= c; a ^= rot(c,16); c += b; \
1047 b -= a; b ^= rot(a,19); a += c; \
1048 c -= b; c ^= rot(b, 4); b += a; \
1050 #define final(a,b,c) { \
1051 c ^= b; c -= rot(b,14); \
1052 a ^= c; a -= rot(c,11); \
1053 b ^= a; b -= rot(a,25); \
1054 c ^= b; c -= rot(b,16); \
1055 a ^= c; a -= rot(c,4); \
1056 b ^= a; b -= rot(a,14); \
1057 c ^= b; c -= rot(b,24); \
1061 * mono_method_get_imt_slot:
1063 * The IMT slot is embedded into AOTed code, so this must return the same value
1064 * for the same method across all executions. This means:
1065 * - pointers shouldn't be used as hash values.
1066 * - mono_metadata_str_hash () should be used for hashing strings.
1069 mono_method_get_imt_slot (MonoMethod *method)
1071 MonoMethodSignature *sig;
1073 guint32 *hashes_start, *hashes;
1077 /* This can be used to stress tests the collision code */
1081 * We do this to simplify generic sharing. It will hurt
1082 * performance in cases where a class implements two different
1083 * instantiations of the same generic interface.
1084 * The code in build_imt_slots () depends on this.
1086 if (method->is_inflated)
1087 method = ((MonoMethodInflated*)method)->declaring;
1089 sig = mono_method_signature (method);
1090 hashes_count = sig->param_count + 4;
1091 hashes_start = malloc (hashes_count * sizeof (guint32));
1092 hashes = hashes_start;
1094 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1095 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1096 method->klass->name_space, method->klass->name, method->name);
1099 /* Initialize hashes */
1100 hashes [0] = mono_metadata_str_hash (method->klass->name);
1101 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1102 hashes [2] = mono_metadata_str_hash (method->name);
1103 hashes [3] = mono_metadata_type_hash (sig->ret);
1104 for (i = 0; i < sig->param_count; i++) {
1105 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1108 /* Setup internal state */
1109 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1111 /* Handle most of the hashes */
1112 while (hashes_count > 3) {
1121 /* Handle the last 3 hashes (all the case statements fall through) */
1122 switch (hashes_count) {
1123 case 3 : c += hashes [2];
1124 case 2 : b += hashes [1];
1125 case 1 : a += hashes [0];
1127 case 0: /* nothing left to add */
1131 free (hashes_start);
1132 /* Report the result */
1133 return c % MONO_IMT_SIZE;
1142 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1143 guint32 imt_slot = mono_method_get_imt_slot (method);
1144 MonoImtBuilderEntry *entry;
1146 if (slot_num >= 0 && imt_slot != slot_num) {
1147 /* we build just a single imt slot and this is not it */
1151 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1152 entry->key = method;
1153 entry->value.vtable_slot = vtable_slot;
1154 entry->next = imt_builder [imt_slot];
1155 if (imt_builder [imt_slot] != NULL) {
1156 entry->children = imt_builder [imt_slot]->children + 1;
1157 if (entry->children == 1) {
1158 mono_stats.imt_slots_with_collisions++;
1159 *imt_collisions_bitmap |= (1 << imt_slot);
1162 entry->children = 0;
1163 mono_stats.imt_used_slots++;
1165 imt_builder [imt_slot] = entry;
1168 char *method_name = mono_method_full_name (method, TRUE);
1169 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1170 method, method_name, imt_slot, vtable_slot, entry->children);
1171 g_free (method_name);
1178 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1180 MonoMethod *method = e->key;
1181 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1185 method->klass->name_space,
1186 method->klass->name,
1189 printf (" * %s: NULL\n", message);
1195 compare_imt_builder_entries (const void *p1, const void *p2) {
1196 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1197 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1199 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1203 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1205 int count = end - start;
1206 int chunk_start = out_array->len;
1209 for (i = start; i < end; ++i) {
1210 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1211 item->key = sorted_array [i]->key;
1212 item->value = sorted_array [i]->value;
1213 item->has_target_code = sorted_array [i]->has_target_code;
1214 item->is_equals = TRUE;
1216 item->check_target_idx = out_array->len + 1;
1218 item->check_target_idx = 0;
1219 g_ptr_array_add (out_array, item);
1222 int middle = start + count / 2;
1223 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1225 item->key = sorted_array [middle]->key;
1226 item->is_equals = FALSE;
1227 g_ptr_array_add (out_array, item);
1228 imt_emit_ir (sorted_array, start, middle, out_array);
1229 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1235 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1236 int number_of_entries = entries->children + 1;
1237 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1238 GPtrArray *result = g_ptr_array_new ();
1239 MonoImtBuilderEntry *current_entry;
1242 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1243 sorted_array [i] = current_entry;
1245 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1247 /*for (i = 0; i < number_of_entries; i++) {
1248 print_imt_entry (" sorted array:", sorted_array [i], i);
1251 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1253 free (sorted_array);
1258 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1260 if (imt_builder_entry != NULL) {
1261 if (imt_builder_entry->children == 0 && !fail_tramp) {
1262 /* No collision, return the vtable slot contents */
1263 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1265 /* Collision, build the thunk */
1266 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1269 result = imt_thunk_builder (vtable, domain,
1270 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1271 for (i = 0; i < imt_ir->len; ++i)
1272 g_free (g_ptr_array_index (imt_ir, i));
1273 g_ptr_array_free (imt_ir, TRUE);
1285 static MonoImtBuilderEntry*
1286 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1289 * LOCKING: requires the loader and domain locks.
1293 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1297 guint32 imt_collisions_bitmap = 0;
1298 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1299 int method_count = 0;
1300 gboolean record_method_count_for_max_collisions = FALSE;
1301 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1304 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1306 for (i = 0; i < klass->interface_offsets_count; ++i) {
1307 MonoClass *iface = klass->interfaces_packed [i];
1308 int interface_offset = klass->interface_offsets_packed [i];
1309 int method_slot_in_interface, vt_slot;
1311 if (mono_class_has_variant_generic_params (iface))
1312 has_variant_iface = TRUE;
1314 mono_class_setup_methods (iface);
1315 vt_slot = interface_offset;
1316 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1319 if (slot_num >= 0 && iface->is_inflated) {
1321 * The imt slot of the method is the same as for its declaring method,
1322 * see the comment in mono_method_get_imt_slot (), so we can
1323 * avoid inflating methods which will be discarded by
1324 * add_imt_builder_entry anyway.
1326 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1327 if (mono_method_get_imt_slot (method) != slot_num) {
1332 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1333 if (method->is_generic) {
1334 has_generic_virtual = TRUE;
1339 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1340 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1345 if (extra_interfaces) {
1346 int interface_offset = klass->vtable_size;
1348 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1349 MonoClass* iface = list_item->data;
1350 int method_slot_in_interface;
1351 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1352 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1354 if (method->is_generic)
1355 has_generic_virtual = TRUE;
1356 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1358 interface_offset += iface->method.count;
1361 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1362 /* overwrite the imt slot only if we're building all the entries or if
1363 * we're building this specific one
1365 if (slot_num < 0 || i == slot_num) {
1366 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1369 if (imt_builder [i]) {
1370 MonoImtBuilderEntry *entry;
1372 /* Link entries with imt_builder [i] */
1373 for (entry = entries; entry->next; entry = entry->next) {
1375 MonoMethod *method = (MonoMethod*)entry->key;
1376 char *method_name = mono_method_full_name (method, TRUE);
1377 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1378 g_free (method_name);
1381 entry->next = imt_builder [i];
1382 entries->children += imt_builder [i]->children + 1;
1384 imt_builder [i] = entries;
1387 if (has_generic_virtual || has_variant_iface) {
1389 * There might be collisions later when the the thunk is expanded.
1391 imt_collisions_bitmap |= (1 << i);
1394 * The IMT thunk might be called with an instance of one of the
1395 * generic virtual methods, so has to fallback to the IMT trampoline.
1397 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1399 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1402 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1406 if (imt_builder [i] != NULL) {
1407 int methods_in_slot = imt_builder [i]->children + 1;
1408 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1409 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1410 record_method_count_for_max_collisions = TRUE;
1412 method_count += methods_in_slot;
1416 mono_stats.imt_number_of_methods += method_count;
1417 if (record_method_count_for_max_collisions) {
1418 mono_stats.imt_method_count_when_max_collisions = method_count;
1421 for (i = 0; i < MONO_IMT_SIZE; i++) {
1422 MonoImtBuilderEntry* entry = imt_builder [i];
1423 while (entry != NULL) {
1424 MonoImtBuilderEntry* next = entry->next;
1430 /* we OR the bitmap since we may build just a single imt slot at a time */
1431 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1435 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1436 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1440 * mono_vtable_build_imt_slot:
1441 * @vtable: virtual object table struct
1442 * @imt_slot: slot in the IMT table
1444 * Fill the given @imt_slot in the IMT table of @vtable with
1445 * a trampoline or a thunk for the case of collisions.
1446 * This is part of the internal mono API.
1448 * LOCKING: Take the domain lock.
1451 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1453 gpointer *imt = (gpointer*)vtable;
1454 imt -= MONO_IMT_SIZE;
1455 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1457 /* no support for extra interfaces: the proxy objects will need
1458 * to build the complete IMT
1459 * Update and heck needs to ahppen inside the proper domain lock, as all
1460 * the changes made to a MonoVTable.
1462 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1463 mono_domain_lock (vtable->domain);
1464 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1465 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1466 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1467 mono_domain_unlock (vtable->domain);
1468 mono_loader_unlock ();
1473 * The first two free list entries both belong to the wait list: The
1474 * first entry is the pointer to the head of the list and the second
1475 * entry points to the last element. That way appending and removing
1476 * the first element are both O(1) operations.
1478 #ifdef MONO_SMALL_CONFIG
1479 #define NUM_FREE_LISTS 6
1481 #define NUM_FREE_LISTS 12
1483 #define FIRST_FREE_LIST_SIZE 64
1484 #define MAX_WAIT_LENGTH 50
1485 #define THUNK_THRESHOLD 10
1488 * LOCKING: The domain lock must be held.
1491 init_thunk_free_lists (MonoDomain *domain)
1493 if (domain->thunk_free_lists)
1495 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1499 list_index_for_size (int item_size)
1502 int size = FIRST_FREE_LIST_SIZE;
1504 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1513 * mono_method_alloc_generic_virtual_thunk:
1515 * @size: size in bytes
1517 * Allocs size bytes to be used for the code of a generic virtual
1518 * thunk. It's either allocated from the domain's code manager or
1519 * reused from a previously invalidated piece.
1521 * LOCKING: The domain lock must be held.
1524 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1526 static gboolean inited = FALSE;
1527 static int generic_virtual_thunks_size = 0;
1531 MonoThunkFreeList **l;
1533 init_thunk_free_lists (domain);
1535 size += sizeof (guint32);
1536 if (size < sizeof (MonoThunkFreeList))
1537 size = sizeof (MonoThunkFreeList);
1539 i = list_index_for_size (size);
1540 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1541 if ((*l)->size >= size) {
1542 MonoThunkFreeList *item = *l;
1544 return ((guint32*)item) + 1;
1548 /* no suitable item found - search lists of larger sizes */
1549 while (++i < NUM_FREE_LISTS) {
1550 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1553 g_assert (item->size > size);
1554 domain->thunk_free_lists [i] = item->next;
1555 return ((guint32*)item) + 1;
1558 /* still nothing found - allocate it */
1560 mono_counters_register ("Generic virtual thunk bytes",
1561 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1564 generic_virtual_thunks_size += size;
1566 p = mono_domain_code_reserve (domain, size);
1569 mono_domain_lock (domain);
1570 if (!domain->generic_virtual_thunks)
1571 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1572 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1573 mono_domain_unlock (domain);
1579 * LOCKING: The domain lock must be held.
1582 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1585 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1586 gboolean found = FALSE;
1588 mono_domain_lock (domain);
1589 if (!domain->generic_virtual_thunks)
1590 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1591 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1593 mono_domain_unlock (domain);
1596 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1598 init_thunk_free_lists (domain);
1600 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1601 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1602 int length = item->length;
1605 /* unlink the first item from the wait list */
1606 domain->thunk_free_lists [0] = item->next;
1607 domain->thunk_free_lists [0]->length = length - 1;
1609 i = list_index_for_size (item->size);
1611 /* put it in the free list */
1612 item->next = domain->thunk_free_lists [i];
1613 domain->thunk_free_lists [i] = item;
1617 if (domain->thunk_free_lists [1]) {
1618 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1619 domain->thunk_free_lists [0]->length++;
1621 g_assert (!domain->thunk_free_lists [0]);
1623 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1624 domain->thunk_free_lists [0]->length = 1;
1628 typedef struct _GenericVirtualCase {
1632 struct _GenericVirtualCase *next;
1633 } GenericVirtualCase;
1636 * get_generic_virtual_entries:
1638 * Return IMT entries for the generic virtual method instances and
1639 * variant interface methods for vtable slot
1642 static MonoImtBuilderEntry*
1643 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1645 GenericVirtualCase *list;
1646 MonoImtBuilderEntry *entries;
1648 mono_domain_lock (domain);
1649 if (!domain->generic_virtual_cases)
1650 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1652 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1655 for (; list; list = list->next) {
1656 MonoImtBuilderEntry *entry;
1658 if (list->count < THUNK_THRESHOLD)
1661 entry = g_new0 (MonoImtBuilderEntry, 1);
1662 entry->key = list->method;
1663 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1664 entry->has_target_code = 1;
1666 entry->children = entries->children + 1;
1667 entry->next = entries;
1671 mono_domain_unlock (domain);
1673 /* FIXME: Leaking memory ? */
1678 * mono_method_add_generic_virtual_invocation:
1680 * @vtable_slot: pointer to the vtable slot
1681 * @method: the inflated generic virtual method
1682 * @code: the method's code
1684 * Registers a call via unmanaged code to a generic virtual method
1685 * instantiation or variant interface method. If the number of calls reaches a threshold
1686 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1687 * virtual method thunk.
1690 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1691 gpointer *vtable_slot,
1692 MonoMethod *method, gpointer code)
1694 static gboolean inited = FALSE;
1695 static int num_added = 0;
1697 GenericVirtualCase *gvc, *list;
1698 MonoImtBuilderEntry *entries;
1702 mono_domain_lock (domain);
1703 if (!domain->generic_virtual_cases)
1704 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1706 /* Check whether the case was already added */
1707 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 if (gvc->method == method)
1715 /* If not found, make a new one */
1717 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1718 gvc->method = method;
1721 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1723 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1726 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1732 if (++gvc->count == THUNK_THRESHOLD) {
1733 gpointer *old_thunk = *vtable_slot;
1734 gpointer vtable_trampoline = NULL;
1735 gpointer imt_trampoline = NULL;
1737 if ((gpointer)vtable_slot < (gpointer)vtable) {
1738 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1739 int imt_slot = MONO_IMT_SIZE + displacement;
1741 /* Force the rebuild of the thunk at the next call */
1742 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1743 *vtable_slot = imt_trampoline;
1745 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1747 entries = get_generic_virtual_entries (domain, vtable_slot);
1749 sorted = imt_sort_slot_entries (entries);
1751 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1755 MonoImtBuilderEntry *next = entries->next;
1760 for (i = 0; i < sorted->len; ++i)
1761 g_free (g_ptr_array_index (sorted, i));
1762 g_ptr_array_free (sorted, TRUE);
1765 #ifndef __native_client__
1766 /* We don't re-use any thunks as there is a lot of overhead */
1767 /* to deleting and re-using code in Native Client. */
1768 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1769 invalidate_generic_virtual_thunk (domain, old_thunk);
1773 mono_domain_unlock (domain);
1776 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1779 * mono_class_vtable:
1780 * @domain: the application domain
1781 * @class: the class to initialize
1783 * VTables are domain specific because we create domain specific code, and
1784 * they contain the domain specific static class data.
1785 * On failure, NULL is returned, and class->exception_type is set.
1788 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1790 return mono_class_vtable_full (domain, class, FALSE);
1794 * mono_class_vtable_full:
1795 * @domain: the application domain
1796 * @class: the class to initialize
1797 * @raise_on_error if an exception should be raised on failure or not
1799 * VTables are domain specific because we create domain specific code, and
1800 * they contain the domain specific static class data.
1803 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1805 MonoClassRuntimeInfo *runtime_info;
1809 if (class->exception_type) {
1811 mono_raise_exception (mono_class_get_exception_for_failure (class));
1815 /* this check can be inlined in jitted code, too */
1816 runtime_info = class->runtime_info;
1817 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1818 return runtime_info->domain_vtables [domain->domain_id];
1819 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1823 * mono_class_try_get_vtable:
1824 * @domain: the application domain
1825 * @class: the class to initialize
1827 * This function tries to get the associated vtable from @class if
1828 * it was already created.
1831 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1833 MonoClassRuntimeInfo *runtime_info;
1837 runtime_info = class->runtime_info;
1838 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1839 return runtime_info->domain_vtables [domain->domain_id];
1844 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1847 MonoClassRuntimeInfo *runtime_info, *old_info;
1848 MonoClassField *field;
1850 int i, vtable_slots;
1851 int imt_table_bytes = 0;
1853 guint32 vtable_size, class_size;
1856 gpointer *interface_offsets;
1858 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1859 mono_domain_lock (domain);
1860 runtime_info = class->runtime_info;
1861 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1862 mono_domain_unlock (domain);
1863 mono_loader_unlock ();
1864 return runtime_info->domain_vtables [domain->domain_id];
1866 if (!class->inited || class->exception_type) {
1867 if (!mono_class_init (class) || class->exception_type) {
1868 mono_domain_unlock (domain);
1869 mono_loader_unlock ();
1871 mono_raise_exception (mono_class_get_exception_for_failure (class));
1876 /* Array types require that their element type be valid*/
1877 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1878 MonoClass *element_class = class->element_class;
1879 if (!element_class->inited)
1880 mono_class_init (element_class);
1882 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1883 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1884 mono_class_setup_vtable (element_class);
1886 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1887 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1888 if (class->exception_type == MONO_EXCEPTION_NONE)
1889 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1890 mono_domain_unlock (domain);
1891 mono_loader_unlock ();
1893 mono_raise_exception (mono_class_get_exception_for_failure (class));
1899 * For some classes, mono_class_init () already computed class->vtable_size, and
1900 * that is all that is needed because of the vtable trampolines.
1902 if (!class->vtable_size)
1903 mono_class_setup_vtable (class);
1905 if (class->generic_class && !class->vtable)
1906 mono_class_check_vtable_constraints (class, NULL);
1908 /* Initialize klass->has_finalize */
1909 mono_class_has_finalizer (class);
1911 if (class->exception_type) {
1912 mono_domain_unlock (domain);
1913 mono_loader_unlock ();
1915 mono_raise_exception (mono_class_get_exception_for_failure (class));
1919 vtable_slots = class->vtable_size;
1920 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1921 class_size = mono_class_data_size (class);
1926 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1927 if (class->interface_offsets_count) {
1928 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1929 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1930 mono_stats.imt_number_of_tables++;
1931 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1934 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1935 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1938 mono_stats.used_class_count++;
1939 mono_stats.class_vtable_size += vtable_size;
1940 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1943 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1945 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1947 vt->rank = class->rank;
1948 vt->domain = domain;
1950 mono_class_compute_gc_descriptor (class);
1952 * We can't use typed allocation in the non-root domains, since the
1953 * collector needs the GC descriptor stored in the vtable even after
1954 * the mempool containing the vtable is destroyed when the domain is
1955 * unloaded. An alternative might be to allocate vtables in the GC
1956 * heap, but this does not seem to work (it leads to crashes inside
1957 * libgc). If that approach is tried, two gc descriptors need to be
1958 * allocated for each class: one for the root domain, and one for all
1959 * other domains. The second descriptor should contain a bit for the
1960 * vtable field in MonoObject, since we can no longer assume the
1961 * vtable is reachable by other roots after the appdomain is unloaded.
1963 #ifdef HAVE_BOEHM_GC
1964 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1965 vt->gc_descr = GC_NO_DESCRIPTOR;
1968 vt->gc_descr = class->gc_descr;
1970 gc_bits = mono_gc_get_vtable_bits (class);
1971 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1973 vt->gc_bits = gc_bits;
1976 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1977 if (class->has_static_refs) {
1978 gpointer statics_gc_descr;
1980 gsize default_bitmap [4] = {0};
1983 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1984 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1985 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1986 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1987 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1988 if (bitmap != default_bitmap)
1991 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1993 vt->has_static_fields = TRUE;
1994 mono_stats.class_static_data_size += class_size;
1999 while ((field = mono_class_get_fields (class, &iter))) {
2000 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2002 if (mono_field_is_deleted (field))
2004 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2005 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2006 if (special_static != SPECIAL_STATIC_NONE) {
2007 guint32 size, offset;
2009 gsize default_bitmap [4] = {0};
2014 if (mono_type_is_reference (field->type)) {
2015 default_bitmap [0] = 1;
2017 bitmap = default_bitmap;
2018 } else if (mono_type_is_struct (field->type)) {
2019 fclass = mono_class_from_mono_type (field->type);
2020 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2021 numbits = max_set + 1;
2023 default_bitmap [0] = 0;
2025 bitmap = default_bitmap;
2027 size = mono_type_size (field->type, &align);
2028 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2029 if (!domain->special_static_fields)
2030 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2031 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2032 if (bitmap != default_bitmap)
2035 * This marks the field as special static to speed up the
2036 * checks in mono_field_static_get/set_value ().
2042 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2043 MonoClass *fklass = mono_class_from_mono_type (field->type);
2044 const char *data = mono_field_get_data (field);
2046 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2047 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2048 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2051 if (fklass->valuetype) {
2052 memcpy (t, data, mono_class_value_size (fklass, NULL));
2054 /* it's a pointer type: add check */
2055 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2062 vt->max_interface_id = class->max_interface_id;
2063 vt->interface_bitmap = class->interface_bitmap;
2065 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2066 // class->name, class->interface_offsets_count);
2068 if (! ARCH_USE_IMT) {
2069 /* initialize interface offsets */
2070 for (i = 0; i < class->interface_offsets_count; ++i) {
2071 int interface_id = class->interfaces_packed [i]->interface_id;
2072 int slot = class->interface_offsets_packed [i];
2073 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2077 /* Initialize vtable */
2078 if (callbacks.get_vtable_trampoline) {
2079 // This also covers the AOT case
2080 for (i = 0; i < class->vtable_size; ++i) {
2081 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2084 mono_class_setup_vtable (class);
2086 for (i = 0; i < class->vtable_size; ++i) {
2089 if ((cm = class->vtable [i]))
2090 vt->vtable [i] = arch_create_jit_trampoline (cm);
2094 if (ARCH_USE_IMT && imt_table_bytes) {
2095 /* Now that the vtable is full, we can actually fill up the IMT */
2096 if (callbacks.get_imt_trampoline) {
2097 /* lazy construction of the IMT entries enabled */
2098 for (i = 0; i < MONO_IMT_SIZE; ++i)
2099 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2101 build_imt (class, vt, domain, interface_offsets, NULL);
2106 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2107 * re-acquire them and check if another thread has created the vtable in the meantime.
2109 /* Special case System.MonoType to avoid infinite recursion */
2110 if (class != mono_defaults.monotype_class) {
2111 /*FIXME check for OOM*/
2112 vt->type = mono_type_get_object (domain, &class->byval_arg);
2113 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2114 /* This is unregistered in
2115 unregister_vtable_reflection_type() in
2117 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2120 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2122 /* class_vtable_array keeps an array of created vtables
2124 g_ptr_array_add (domain->class_vtable_array, vt);
2125 /* class->runtime_info is protected by the loader lock, both when
2126 * it it enlarged and when it is stored info.
2130 * Store the vtable in class->runtime_info.
2131 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2133 mono_memory_barrier ();
2135 old_info = class->runtime_info;
2136 if (old_info && old_info->max_domain >= domain->domain_id) {
2137 /* someone already created a large enough runtime info */
2138 old_info->domain_vtables [domain->domain_id] = vt;
2140 int new_size = domain->domain_id;
2142 new_size = MAX (new_size, old_info->max_domain);
2144 /* make the new size a power of two */
2146 while (new_size > i)
2149 /* this is a bounded memory retention issue: may want to
2150 * handle it differently when we'll have a rcu-like system.
2152 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2153 runtime_info->max_domain = new_size - 1;
2154 /* copy the stuff from the older info */
2156 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2158 runtime_info->domain_vtables [domain->domain_id] = vt;
2160 mono_memory_barrier ();
2161 class->runtime_info = runtime_info;
2164 if (class == mono_defaults.monotype_class) {
2165 /*FIXME check for OOM*/
2166 vt->type = mono_type_get_object (domain, &class->byval_arg);
2167 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2168 /* This is unregistered in
2169 unregister_vtable_reflection_type() in
2171 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2174 mono_domain_unlock (domain);
2175 mono_loader_unlock ();
2177 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2178 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2179 mono_raise_exception (mono_class_get_exception_for_failure (class));
2181 /* make sure the parent is initialized */
2182 /*FIXME shouldn't this fail the current type?*/
2184 mono_class_vtable_full (domain, class->parent, raise_on_error);
2189 #ifndef DISABLE_REMOTING
2191 * mono_class_proxy_vtable:
2192 * @domain: the application domain
2193 * @remove_class: the remote class
2195 * Creates a vtable for transparent proxies. It is basically
2196 * a copy of the real vtable of the class wrapped in @remote_class,
2197 * but all function pointers invoke the remoting functions, and
2198 * vtable->klass points to the transparent proxy class, and not to @class.
2201 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2204 MonoVTable *vt, *pvt;
2205 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2207 GSList *extra_interfaces = NULL;
2208 MonoClass *class = remote_class->proxy_class;
2209 gpointer *interface_offsets;
2213 #ifdef COMPRESSED_INTERFACE_BITMAP
2217 vt = mono_class_vtable (domain, class);
2218 g_assert (vt); /*FIXME property handle failure*/
2219 max_interface_id = vt->max_interface_id;
2221 /* Calculate vtable space for extra interfaces */
2222 for (j = 0; j < remote_class->interface_count; j++) {
2223 MonoClass* iclass = remote_class->interfaces[j];
2227 /*FIXME test for interfaces with variant generic arguments*/
2228 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2229 continue; /* interface implemented by the class */
2230 if (g_slist_find (extra_interfaces, iclass))
2233 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2235 method_count = mono_class_num_methods (iclass);
2237 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2238 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2240 for (i = 0; i < ifaces->len; ++i) {
2241 MonoClass *ic = g_ptr_array_index (ifaces, i);
2242 /*FIXME test for interfaces with variant generic arguments*/
2243 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2244 continue; /* interface implemented by the class */
2245 if (g_slist_find (extra_interfaces, ic))
2247 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2248 method_count += mono_class_num_methods (ic);
2250 g_ptr_array_free (ifaces, TRUE);
2253 extra_interface_vtsize += method_count * sizeof (gpointer);
2254 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2258 mono_stats.imt_number_of_tables++;
2259 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2260 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2261 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2263 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2264 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2267 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2269 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2271 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2273 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2274 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2276 pvt->klass = mono_defaults.transparent_proxy_class;
2277 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2278 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2280 /* initialize vtable */
2281 mono_class_setup_vtable (class);
2282 for (i = 0; i < class->vtable_size; ++i) {
2285 if ((cm = class->vtable [i]))
2286 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2288 pvt->vtable [i] = NULL;
2291 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2292 /* create trampolines for abstract methods */
2293 for (k = class; k; k = k->parent) {
2295 gpointer iter = NULL;
2296 while ((m = mono_class_get_methods (k, &iter)))
2297 if (!pvt->vtable [m->slot])
2298 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2302 pvt->max_interface_id = max_interface_id;
2303 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2304 #ifdef COMPRESSED_INTERFACE_BITMAP
2305 bitmap = g_malloc0 (bsize);
2307 bitmap = mono_domain_alloc0 (domain, bsize);
2310 if (! ARCH_USE_IMT) {
2311 /* initialize interface offsets */
2312 for (i = 0; i < class->interface_offsets_count; ++i) {
2313 int interface_id = class->interfaces_packed [i]->interface_id;
2314 int slot = class->interface_offsets_packed [i];
2315 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2318 for (i = 0; i < class->interface_offsets_count; ++i) {
2319 int interface_id = class->interfaces_packed [i]->interface_id;
2320 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2323 if (extra_interfaces) {
2324 int slot = class->vtable_size;
2330 /* Create trampolines for the methods of the interfaces */
2331 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2332 interf = list_item->data;
2334 if (! ARCH_USE_IMT) {
2335 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2337 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2341 while ((cm = mono_class_get_methods (interf, &iter)))
2342 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2344 slot += mono_class_num_methods (interf);
2346 if (! ARCH_USE_IMT) {
2347 g_slist_free (extra_interfaces);
2352 /* Now that the vtable is full, we can actually fill up the IMT */
2353 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2354 if (extra_interfaces) {
2355 g_slist_free (extra_interfaces);
2359 #ifdef COMPRESSED_INTERFACE_BITMAP
2360 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2361 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2362 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2365 pvt->interface_bitmap = bitmap;
2370 #endif /* DISABLE_REMOTING */
2373 * mono_class_field_is_special_static:
2375 * Returns whether @field is a thread/context static field.
2378 mono_class_field_is_special_static (MonoClassField *field)
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2382 if (mono_field_is_deleted (field))
2384 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2385 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2392 * mono_class_field_get_special_static_type:
2393 * @field: The MonoClassField describing the field.
2395 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2396 * SPECIAL_STATIC_NONE otherwise.
2399 mono_class_field_get_special_static_type (MonoClassField *field)
2401 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2402 return SPECIAL_STATIC_NONE;
2403 if (mono_field_is_deleted (field))
2404 return SPECIAL_STATIC_NONE;
2405 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2406 return field_is_special_static (field->parent, field);
2407 return SPECIAL_STATIC_NONE;
2411 * mono_class_has_special_static_fields:
2413 * Returns whenever @klass has any thread/context static fields.
2416 mono_class_has_special_static_fields (MonoClass *klass)
2418 MonoClassField *field;
2422 while ((field = mono_class_get_fields (klass, &iter))) {
2423 g_assert (field->parent == klass);
2424 if (mono_class_field_is_special_static (field))
2431 #ifndef DISABLE_REMOTING
2433 * create_remote_class_key:
2434 * Creates an array of pointers that can be used as a hash key for a remote class.
2435 * The first element of the array is the number of pointers.
2438 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2443 if (remote_class == NULL) {
2444 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2445 key = g_malloc (sizeof(gpointer) * 3);
2446 key [0] = GINT_TO_POINTER (2);
2447 key [1] = mono_defaults.marshalbyrefobject_class;
2448 key [2] = extra_class;
2450 key = g_malloc (sizeof(gpointer) * 2);
2451 key [0] = GINT_TO_POINTER (1);
2452 key [1] = extra_class;
2455 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2456 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2457 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2458 key [1] = remote_class->proxy_class;
2460 // Keep the list of interfaces sorted
2461 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2462 if (extra_class && remote_class->interfaces [i] > extra_class) {
2463 key [j++] = extra_class;
2466 key [j] = remote_class->interfaces [i];
2469 key [j] = extra_class;
2471 // Replace the old class. The interface list is the same
2472 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2473 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2474 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2475 for (i = 0; i < remote_class->interface_count; i++)
2476 key [2 + i] = remote_class->interfaces [i];
2484 * copy_remote_class_key:
2486 * Make a copy of KEY in the domain and return the copy.
2489 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2491 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2492 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2494 memcpy (mp_key, key, key_size);
2500 * mono_remote_class:
2501 * @domain: the application domain
2502 * @class_name: name of the remote class
2504 * Creates and initializes a MonoRemoteClass object for a remote type.
2506 * Can raise an exception on failure.
2509 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2512 MonoRemoteClass *rc;
2513 gpointer* key, *mp_key;
2516 key = create_remote_class_key (NULL, proxy_class);
2518 mono_domain_lock (domain);
2519 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2523 mono_domain_unlock (domain);
2527 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2528 if (!mono_error_ok (&error)) {
2530 mono_domain_unlock (domain);
2531 mono_error_raise_exception (&error);
2534 mp_key = copy_remote_class_key (domain, key);
2538 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2539 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2540 rc->interface_count = 1;
2541 rc->interfaces [0] = proxy_class;
2542 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2544 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2545 rc->interface_count = 0;
2546 rc->proxy_class = proxy_class;
2549 rc->default_vtable = NULL;
2550 rc->xdomain_vtable = NULL;
2551 rc->proxy_class_name = name;
2552 #ifndef DISABLE_PERFCOUNTERS
2553 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2556 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2558 mono_domain_unlock (domain);
2563 * clone_remote_class:
2564 * Creates a copy of the remote_class, adding the provided class or interface
2566 static MonoRemoteClass*
2567 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2569 MonoRemoteClass *rc;
2570 gpointer* key, *mp_key;
2572 key = create_remote_class_key (remote_class, extra_class);
2573 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2579 mp_key = copy_remote_class_key (domain, key);
2583 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2585 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2586 rc->proxy_class = remote_class->proxy_class;
2587 rc->interface_count = remote_class->interface_count + 1;
2589 // Keep the list of interfaces sorted, since the hash key of
2590 // the remote class depends on this
2591 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2592 if (remote_class->interfaces [i] > extra_class && i == j)
2593 rc->interfaces [j++] = extra_class;
2594 rc->interfaces [j] = remote_class->interfaces [i];
2597 rc->interfaces [j] = extra_class;
2599 // Replace the old class. The interface array is the same
2600 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2601 rc->proxy_class = extra_class;
2602 rc->interface_count = remote_class->interface_count;
2603 if (rc->interface_count > 0)
2604 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2607 rc->default_vtable = NULL;
2608 rc->xdomain_vtable = NULL;
2609 rc->proxy_class_name = remote_class->proxy_class_name;
2611 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2617 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2619 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2620 mono_domain_lock (domain);
2621 if (rp->target_domain_id != -1) {
2622 if (remote_class->xdomain_vtable == NULL)
2623 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2624 mono_domain_unlock (domain);
2625 mono_loader_unlock ();
2626 return remote_class->xdomain_vtable;
2628 if (remote_class->default_vtable == NULL) {
2631 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2632 klass = mono_class_from_mono_type (type);
2634 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2635 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2638 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2641 mono_domain_unlock (domain);
2642 mono_loader_unlock ();
2643 return remote_class->default_vtable;
2647 * mono_upgrade_remote_class:
2648 * @domain: the application domain
2649 * @tproxy: the proxy whose remote class has to be upgraded.
2650 * @klass: class to which the remote class can be casted.
2652 * Updates the vtable of the remote class by adding the necessary method slots
2653 * and interface offsets so it can be safely casted to klass. klass can be a
2654 * class or an interface.
2657 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2659 MonoTransparentProxy *tproxy;
2660 MonoRemoteClass *remote_class;
2661 gboolean redo_vtable;
2663 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2664 mono_domain_lock (domain);
2666 tproxy = (MonoTransparentProxy*) proxy_object;
2667 remote_class = tproxy->remote_class;
2669 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2672 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2673 if (remote_class->interfaces [i] == klass)
2674 redo_vtable = FALSE;
2677 redo_vtable = (remote_class->proxy_class != klass);
2681 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2682 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2685 mono_domain_unlock (domain);
2686 mono_loader_unlock ();
2688 #endif /* DISABLE_REMOTING */
2692 * mono_object_get_virtual_method:
2693 * @obj: object to operate on.
2696 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2697 * the instance of a callvirt of method.
2700 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2703 MonoMethod **vtable;
2704 gboolean is_proxy = FALSE;
2705 MonoMethod *res = NULL;
2707 klass = mono_object_class (obj);
2708 #ifndef DISABLE_REMOTING
2709 if (klass == mono_defaults.transparent_proxy_class) {
2710 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2715 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2718 mono_class_setup_vtable (klass);
2719 vtable = klass->vtable;
2721 if (method->slot == -1) {
2722 /* method->slot might not be set for instances of generic methods */
2723 if (method->is_inflated) {
2724 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2725 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2728 g_assert_not_reached ();
2732 /* check method->slot is a valid index: perform isinstance? */
2733 if (method->slot != -1) {
2734 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2736 gboolean variance_used = FALSE;
2737 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2738 g_assert (iface_offset > 0);
2739 res = vtable [iface_offset + method->slot];
2742 res = vtable [method->slot];
2746 #ifndef DISABLE_REMOTING
2748 /* It may be an interface, abstract class method or generic method */
2749 if (!res || mono_method_signature (res)->generic_param_count)
2752 /* generic methods demand invoke_with_check */
2753 if (mono_method_signature (res)->generic_param_count)
2754 res = mono_marshal_get_remoting_invoke_with_check (res);
2757 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2758 res = mono_cominterop_get_invoke (res);
2761 res = mono_marshal_get_remoting_invoke (res);
2766 if (method->is_inflated) {
2767 /* Have to inflate the result */
2768 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2778 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2780 g_error ("runtime invoke called on uninitialized runtime");
2784 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2787 * mono_runtime_invoke:
2788 * @method: method to invoke
2789 * @obJ: object instance
2790 * @params: arguments to the method
2791 * @exc: exception information.
2793 * Invokes the method represented by @method on the object @obj.
2795 * obj is the 'this' pointer, it should be NULL for static
2796 * methods, a MonoObject* for object instances and a pointer to
2797 * the value type for value types.
2799 * The params array contains the arguments to the method with the
2800 * same convention: MonoObject* pointers for object instances and
2801 * pointers to the value type otherwise.
2803 * From unmanaged code you'll usually use the
2804 * mono_runtime_invoke() variant.
2806 * Note that this function doesn't handle virtual methods for
2807 * you, it will exec the exact method you pass: we still need to
2808 * expose a function to lookup the derived class implementation
2809 * of a virtual method (there are examples of this in the code,
2812 * You can pass NULL as the exc argument if you don't want to
2813 * catch exceptions, otherwise, *exc will be set to the exception
2814 * thrown, if any. if an exception is thrown, you can't use the
2815 * MonoObject* result from the function.
2817 * If the method returns a value type, it is boxed in an object
2821 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2825 if (mono_runtime_get_no_exec ())
2826 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2828 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2829 mono_profiler_method_start_invoke (method);
2831 result = default_mono_runtime_invoke (method, obj, params, exc);
2833 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2834 mono_profiler_method_end_invoke (method);
2840 * mono_method_get_unmanaged_thunk:
2841 * @method: method to generate a thunk for.
2843 * Returns an unmanaged->managed thunk that can be used to call
2844 * a managed method directly from C.
2846 * The thunk's C signature closely matches the managed signature:
2848 * C#: public bool Equals (object obj);
2849 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2850 * MonoObject*, MonoException**);
2852 * The 1st ("this") parameter must not be used with static methods:
2854 * C#: public static bool ReferenceEquals (object a, object b);
2855 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2858 * The last argument must be a non-null pointer of a MonoException* pointer.
2859 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2860 * exception has been thrown in managed code. Otherwise it will point
2861 * to the MonoException* caught by the thunk. In this case, the result of
2862 * the thunk is undefined:
2864 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2865 * MonoException *ex = NULL;
2866 * Equals func = mono_method_get_unmanaged_thunk (method);
2867 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2869 * // handle exception
2872 * The calling convention of the thunk matches the platform's default
2873 * convention. This means that under Windows, C declarations must
2874 * contain the __stdcall attribute:
2876 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2877 * MonoObject*, MonoException**);
2881 * Value type arguments and return values are treated as they were objects:
2883 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2884 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2886 * Arguments must be properly boxed upon trunk's invocation, while return
2887 * values must be unboxed.
2890 mono_method_get_unmanaged_thunk (MonoMethod *method)
2892 method = mono_marshal_get_thunk_invoke_wrapper (method);
2893 return mono_compile_method (method);
2897 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2901 /* object fields cannot be byref, so we don't need a
2903 gpointer *p = (gpointer*)dest;
2910 case MONO_TYPE_BOOLEAN:
2912 case MONO_TYPE_U1: {
2913 guint8 *p = (guint8*)dest;
2914 *p = value ? *(guint8*)value : 0;
2919 case MONO_TYPE_CHAR: {
2920 guint16 *p = (guint16*)dest;
2921 *p = value ? *(guint16*)value : 0;
2924 #if SIZEOF_VOID_P == 4
2929 case MONO_TYPE_U4: {
2930 gint32 *p = (gint32*)dest;
2931 *p = value ? *(gint32*)value : 0;
2934 #if SIZEOF_VOID_P == 8
2939 case MONO_TYPE_U8: {
2940 gint64 *p = (gint64*)dest;
2941 *p = value ? *(gint64*)value : 0;
2944 case MONO_TYPE_R4: {
2945 float *p = (float*)dest;
2946 *p = value ? *(float*)value : 0;
2949 case MONO_TYPE_R8: {
2950 double *p = (double*)dest;
2951 *p = value ? *(double*)value : 0;
2954 case MONO_TYPE_STRING:
2955 case MONO_TYPE_SZARRAY:
2956 case MONO_TYPE_CLASS:
2957 case MONO_TYPE_OBJECT:
2958 case MONO_TYPE_ARRAY:
2959 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2961 case MONO_TYPE_FNPTR:
2962 case MONO_TYPE_PTR: {
2963 gpointer *p = (gpointer*)dest;
2964 *p = deref_pointer? *(gpointer*)value: value;
2967 case MONO_TYPE_VALUETYPE:
2968 /* note that 't' and 'type->type' can be different */
2969 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2970 t = mono_class_enum_basetype (type->data.klass)->type;
2973 MonoClass *class = mono_class_from_mono_type (type);
2974 int size = mono_class_value_size (class, NULL);
2976 mono_gc_bzero_atomic (dest, size);
2978 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2981 case MONO_TYPE_GENERICINST:
2982 t = type->data.generic_class->container_class->byval_arg.type;
2985 g_error ("got type %x", type->type);
2990 * mono_field_set_value:
2991 * @obj: Instance object
2992 * @field: MonoClassField describing the field to set
2993 * @value: The value to be set
2995 * Sets the value of the field described by @field in the object instance @obj
2996 * to the value passed in @value. This method should only be used for instance
2997 * fields. For static fields, use mono_field_static_set_value.
2999 * The value must be on the native format of the field type.
3002 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3006 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3008 dest = (char*)obj + field->offset;
3009 set_value (field->type, dest, value, FALSE);
3013 * mono_field_static_set_value:
3014 * @field: MonoClassField describing the field to set
3015 * @value: The value to be set
3017 * Sets the value of the static field described by @field
3018 * to the value passed in @value.
3020 * The value must be on the native format of the field type.
3023 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3027 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3028 /* you cant set a constant! */
3029 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3031 if (field->offset == -1) {
3032 /* Special static */
3035 mono_domain_lock (vt->domain);
3036 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3037 mono_domain_unlock (vt->domain);
3038 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3040 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3042 set_value (field->type, dest, value, FALSE);
3046 * mono_vtable_get_static_field_data:
3048 * Internal use function: return a pointer to the memory holding the static fields
3049 * for a class or NULL if there are no static fields.
3050 * This is exported only for use by the debugger.
3053 mono_vtable_get_static_field_data (MonoVTable *vt)
3055 if (!vt->has_static_fields)
3057 return vt->vtable [vt->klass->vtable_size];
3061 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3065 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3066 if (field->offset == -1) {
3067 /* Special static */
3070 mono_domain_lock (vt->domain);
3071 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3072 mono_domain_unlock (vt->domain);
3073 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3075 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3078 src = (guint8*)obj + field->offset;
3085 * mono_field_get_value:
3086 * @obj: Object instance
3087 * @field: MonoClassField describing the field to fetch information from
3088 * @value: pointer to the location where the value will be stored
3090 * Use this routine to get the value of the field @field in the object
3093 * The pointer provided by value must be of the field type, for reference
3094 * types this is a MonoObject*, for value types its the actual pointer to
3099 * mono_field_get_value (obj, int_field, &i);
3102 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3108 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3110 src = (char*)obj + field->offset;
3111 set_value (field->type, value, src, TRUE);
3115 * mono_field_get_value_object:
3116 * @domain: domain where the object will be created (if boxing)
3117 * @field: MonoClassField describing the field to fetch information from
3118 * @obj: The object instance for the field.
3120 * Returns: a new MonoObject with the value from the given field. If the
3121 * field represents a value type, the value is boxed.
3125 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3129 MonoVTable *vtable = NULL;
3131 gboolean is_static = FALSE;
3132 gboolean is_ref = FALSE;
3133 gboolean is_literal = FALSE;
3134 gboolean is_ptr = FALSE;
3136 MonoType *type = mono_field_get_type_checked (field, &error);
3138 if (!mono_error_ok (&error))
3139 mono_error_raise_exception (&error);
3141 switch (type->type) {
3142 case MONO_TYPE_STRING:
3143 case MONO_TYPE_OBJECT:
3144 case MONO_TYPE_CLASS:
3145 case MONO_TYPE_ARRAY:
3146 case MONO_TYPE_SZARRAY:
3151 case MONO_TYPE_BOOLEAN:
3154 case MONO_TYPE_CHAR:
3163 case MONO_TYPE_VALUETYPE:
3164 is_ref = type->byref;
3166 case MONO_TYPE_GENERICINST:
3167 is_ref = !mono_type_generic_inst_is_valuetype (type);
3173 g_error ("type 0x%x not handled in "
3174 "mono_field_get_value_object", type->type);
3178 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3181 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3185 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3186 if (!vtable->initialized)
3187 mono_runtime_class_init (vtable);
3195 get_default_field_value (domain, field, &o);
3196 } else if (is_static) {
3197 mono_field_static_get_value (vtable, field, &o);
3199 mono_field_get_value (obj, field, &o);
3205 static MonoMethod *m;
3211 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3212 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3218 get_default_field_value (domain, field, v);
3219 } else if (is_static) {
3220 mono_field_static_get_value (vtable, field, v);
3222 mono_field_get_value (obj, field, v);
3225 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3227 args [1] = mono_type_get_object (mono_domain_get (), type);
3229 return mono_runtime_invoke (m, NULL, args, NULL);
3232 /* boxed value type */
3233 klass = mono_class_from_mono_type (type);
3235 if (mono_class_is_nullable (klass))
3236 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3238 o = mono_object_new (domain, klass);
3239 v = ((gchar *) o) + sizeof (MonoObject);
3242 get_default_field_value (domain, field, v);
3243 } else if (is_static) {
3244 mono_field_static_get_value (vtable, field, v);
3246 mono_field_get_value (obj, field, v);
3253 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3256 const char *p = blob;
3257 mono_metadata_decode_blob_size (p, &p);
3260 case MONO_TYPE_BOOLEAN:
3263 *(guint8 *) value = *p;
3265 case MONO_TYPE_CHAR:
3268 *(guint16*) value = read16 (p);
3272 *(guint32*) value = read32 (p);
3276 *(guint64*) value = read64 (p);
3279 readr4 (p, (float*) value);
3282 readr8 (p, (double*) value);
3284 case MONO_TYPE_STRING:
3285 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3287 case MONO_TYPE_CLASS:
3288 *(gpointer*) value = NULL;
3292 g_warning ("type 0x%02x should not be in constant table", type);
3298 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3300 MonoTypeEnum def_type;
3303 data = mono_class_get_field_default_value (field, &def_type);
3304 mono_get_constant_value_from_blob (domain, def_type, data, value);
3308 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3312 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3314 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3315 get_default_field_value (vt->domain, field, value);
3319 if (field->offset == -1) {
3320 /* Special static */
3321 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3322 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3324 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3326 set_value (field->type, value, src, TRUE);
3330 * mono_field_static_get_value:
3331 * @vt: vtable to the object
3332 * @field: MonoClassField describing the field to fetch information from
3333 * @value: where the value is returned
3335 * Use this routine to get the value of the static field @field value.
3337 * The pointer provided by value must be of the field type, for reference
3338 * types this is a MonoObject*, for value types its the actual pointer to
3343 * mono_field_static_get_value (vt, int_field, &i);
3346 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3348 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3352 * mono_property_set_value:
3353 * @prop: MonoProperty to set
3354 * @obj: instance object on which to act
3355 * @params: parameters to pass to the propery
3356 * @exc: optional exception
3358 * Invokes the property's set method with the given arguments on the
3359 * object instance obj (or NULL for static properties).
3361 * You can pass NULL as the exc argument if you don't want to
3362 * catch exceptions, otherwise, *exc will be set to the exception
3363 * thrown, if any. if an exception is thrown, you can't use the
3364 * MonoObject* result from the function.
3367 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3369 default_mono_runtime_invoke (prop->set, obj, params, exc);
3373 * mono_property_get_value:
3374 * @prop: MonoProperty to fetch
3375 * @obj: instance object on which to act
3376 * @params: parameters to pass to the propery
3377 * @exc: optional exception
3379 * Invokes the property's get method with the given arguments on the
3380 * object instance obj (or NULL for static properties).
3382 * You can pass NULL as the exc argument if you don't want to
3383 * catch exceptions, otherwise, *exc will be set to the exception
3384 * thrown, if any. if an exception is thrown, you can't use the
3385 * MonoObject* result from the function.
3387 * Returns: the value from invoking the get method on the property.
3390 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3392 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3396 * mono_nullable_init:
3397 * @buf: The nullable structure to initialize.
3398 * @value: the value to initialize from
3399 * @klass: the type for the object
3401 * Initialize the nullable structure pointed to by @buf from @value which
3402 * should be a boxed value type. The size of @buf should be able to hold
3403 * as much data as the @klass->instance_size (which is the number of bytes
3404 * that will be copies).
3406 * Since Nullables have variable structure, we can not define a C
3407 * structure for them.
3410 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3412 MonoClass *param_class = klass->cast_class;
3414 mono_class_setup_fields_locking (klass);
3415 g_assert (klass->fields_inited);
3417 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3418 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3420 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3422 if (param_class->has_references)
3423 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3425 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3427 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3432 * mono_nullable_box:
3433 * @buf: The buffer representing the data to be boxed
3434 * @klass: the type to box it as.
3436 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3440 mono_nullable_box (guint8 *buf, MonoClass *klass)
3442 MonoClass *param_class = klass->cast_class;
3444 mono_class_setup_fields_locking (klass);
3445 g_assert (klass->fields_inited);
3447 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3448 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3450 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3451 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3452 if (param_class->has_references)
3453 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3455 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3463 * mono_get_delegate_invoke:
3464 * @klass: The delegate class
3466 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3469 mono_get_delegate_invoke (MonoClass *klass)
3473 /* This is called at runtime, so avoid the slower search in metadata */
3474 mono_class_setup_methods (klass);
3475 if (klass->exception_type)
3477 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3482 * mono_get_delegate_begin_invoke:
3483 * @klass: The delegate class
3485 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3488 mono_get_delegate_begin_invoke (MonoClass *klass)
3492 /* This is called at runtime, so avoid the slower search in metadata */
3493 mono_class_setup_methods (klass);
3494 if (klass->exception_type)
3496 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3501 * mono_get_delegate_end_invoke:
3502 * @klass: The delegate class
3504 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3507 mono_get_delegate_end_invoke (MonoClass *klass)
3511 /* This is called at runtime, so avoid the slower search in metadata */
3512 mono_class_setup_methods (klass);
3513 if (klass->exception_type)
3515 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3520 * mono_runtime_delegate_invoke:
3521 * @delegate: pointer to a delegate object.
3522 * @params: parameters for the delegate.
3523 * @exc: Pointer to the exception result.
3525 * Invokes the delegate method @delegate with the parameters provided.
3527 * You can pass NULL as the exc argument if you don't want to
3528 * catch exceptions, otherwise, *exc will be set to the exception
3529 * thrown, if any. if an exception is thrown, you can't use the
3530 * MonoObject* result from the function.
3533 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3536 MonoClass *klass = delegate->vtable->klass;
3538 im = mono_get_delegate_invoke (klass);
3540 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3542 return mono_runtime_invoke (im, delegate, params, exc);
3545 static char **main_args = NULL;
3546 static int num_main_args = 0;
3549 * mono_runtime_get_main_args:
3551 * Returns: a MonoArray with the arguments passed to the main program
3554 mono_runtime_get_main_args (void)
3558 MonoDomain *domain = mono_domain_get ();
3560 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3562 for (i = 0; i < num_main_args; ++i)
3563 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3569 free_main_args (void)
3573 for (i = 0; i < num_main_args; ++i)
3574 g_free (main_args [i]);
3581 * mono_runtime_set_main_args:
3582 * @argc: number of arguments from the command line
3583 * @argv: array of strings from the command line
3585 * Set the command line arguments from an embedding application that doesn't otherwise call
3586 * mono_runtime_run_main ().
3589 mono_runtime_set_main_args (int argc, char* argv[])
3594 main_args = g_new0 (char*, argc);
3595 num_main_args = argc;
3597 for (i = 0; i < argc; ++i) {
3600 utf8_arg = mono_utf8_from_external (argv[i]);
3601 if (utf8_arg == NULL) {
3602 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3603 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3607 main_args [i] = utf8_arg;
3614 * mono_runtime_run_main:
3615 * @method: the method to start the application with (usually Main)
3616 * @argc: number of arguments from the command line
3617 * @argv: array of strings from the command line
3618 * @exc: excetption results
3620 * Execute a standard Main() method (argc/argv contains the
3621 * executable name). This method also sets the command line argument value
3622 * needed by System.Environment.
3627 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3631 MonoArray *args = NULL;
3632 MonoDomain *domain = mono_domain_get ();
3633 gchar *utf8_fullpath;
3634 MonoMethodSignature *sig;
3636 g_assert (method != NULL);
3638 mono_thread_set_main (mono_thread_current ());
3640 main_args = g_new0 (char*, argc);
3641 num_main_args = argc;
3643 if (!g_path_is_absolute (argv [0])) {
3644 gchar *basename = g_path_get_basename (argv [0]);
3645 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3649 utf8_fullpath = mono_utf8_from_external (fullpath);
3650 if(utf8_fullpath == NULL) {
3651 /* Printing the arg text will cause glib to
3652 * whinge about "Invalid UTF-8", but at least
3653 * its relevant, and shows the problem text
3656 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3657 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3664 utf8_fullpath = mono_utf8_from_external (argv[0]);
3665 if(utf8_fullpath == NULL) {
3666 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3667 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3672 main_args [0] = utf8_fullpath;
3674 for (i = 1; i < argc; ++i) {
3677 utf8_arg=mono_utf8_from_external (argv[i]);
3678 if(utf8_arg==NULL) {
3679 /* Ditto the comment about Invalid UTF-8 here */
3680 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3681 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3685 main_args [i] = utf8_arg;
3690 sig = mono_method_signature (method);
3692 g_print ("Unable to load Main method.\n");
3696 if (sig->param_count) {
3697 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3698 for (i = 0; i < argc; ++i) {
3699 /* The encodings should all work, given that
3700 * we've checked all these args for the
3703 gchar *str = mono_utf8_from_external (argv [i]);
3704 MonoString *arg = mono_string_new (domain, str);
3705 mono_array_setref (args, i, arg);
3709 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3712 mono_assembly_set_main (method->klass->image->assembly);
3714 return mono_runtime_exec_main (method, args, exc);
3718 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3720 static MonoMethod *serialize_method;
3725 if (!serialize_method) {
3726 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3727 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3730 if (!serialize_method) {
3735 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3739 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3747 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3749 static MonoMethod *deserialize_method;
3754 if (!deserialize_method) {
3755 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3756 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3758 if (!deserialize_method) {
3765 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3772 #ifndef DISABLE_REMOTING
3774 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3776 static MonoMethod *get_proxy_method;
3778 MonoDomain *domain = mono_domain_get ();
3779 MonoRealProxy *real_proxy;
3780 MonoReflectionType *reflection_type;
3781 MonoTransparentProxy *transparent_proxy;
3783 if (!get_proxy_method)
3784 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3786 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3788 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3789 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3791 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3792 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3795 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3799 return (MonoObject*) transparent_proxy;
3801 #endif /* DISABLE_REMOTING */
3804 * mono_object_xdomain_representation
3806 * @target_domain: a domain
3807 * @exc: pointer to a MonoObject*
3809 * Creates a representation of obj in the domain target_domain. This
3810 * is either a copy of obj arrived through via serialization and
3811 * deserialization or a proxy, depending on whether the object is
3812 * serializable or marshal by ref. obj must not be in target_domain.
3814 * If the object cannot be represented in target_domain, NULL is
3815 * returned and *exc is set to an appropriate exception.
3818 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3820 MonoObject *deserialized = NULL;
3821 gboolean failure = FALSE;
3825 #ifndef DISABLE_REMOTING
3826 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3827 deserialized = make_transparent_proxy (obj, &failure, exc);
3832 MonoDomain *domain = mono_domain_get ();
3833 MonoObject *serialized;
3835 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3836 serialized = serialize_object (obj, &failure, exc);
3837 mono_domain_set_internal_with_options (target_domain, FALSE);
3839 deserialized = deserialize_object (serialized, &failure, exc);
3840 if (domain != target_domain)
3841 mono_domain_set_internal_with_options (domain, FALSE);
3844 return deserialized;
3847 /* Used in call_unhandled_exception_delegate */
3849 create_unhandled_exception_eventargs (MonoObject *exc)
3853 MonoMethod *method = NULL;
3854 MonoBoolean is_terminating = TRUE;
3857 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3860 mono_class_init (klass);
3862 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3863 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3867 args [1] = &is_terminating;
3869 obj = mono_object_new (mono_domain_get (), klass);
3870 mono_runtime_invoke (method, obj, args, NULL);
3875 /* Used in mono_unhandled_exception */
3877 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3878 MonoObject *e = NULL;
3880 MonoDomain *current_domain = mono_domain_get ();
3882 if (domain != current_domain)
3883 mono_domain_set_internal_with_options (domain, FALSE);
3885 g_assert (domain == mono_object_domain (domain->domain));
3887 if (mono_object_domain (exc) != domain) {
3888 MonoObject *serialization_exc;
3890 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3892 if (serialization_exc) {
3894 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3897 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3898 "System.Runtime.Serialization", "SerializationException",
3899 "Could not serialize unhandled exception.");
3903 g_assert (mono_object_domain (exc) == domain);
3905 pa [0] = domain->domain;
3906 pa [1] = create_unhandled_exception_eventargs (exc);
3907 mono_runtime_delegate_invoke (delegate, pa, &e);
3909 if (domain != current_domain)
3910 mono_domain_set_internal_with_options (current_domain, FALSE);
3914 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3915 if (!mono_error_ok (&error)) {
3916 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3917 mono_error_cleanup (&error);
3919 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3925 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3928 * mono_runtime_unhandled_exception_policy_set:
3929 * @policy: the new policy
3931 * This is a VM internal routine.
3933 * Sets the runtime policy for handling unhandled exceptions.
3936 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3937 runtime_unhandled_exception_policy = policy;
3941 * mono_runtime_unhandled_exception_policy_get:
3943 * This is a VM internal routine.
3945 * Gets the runtime policy for handling unhandled exceptions.
3947 MonoRuntimeUnhandledExceptionPolicy
3948 mono_runtime_unhandled_exception_policy_get (void) {
3949 return runtime_unhandled_exception_policy;
3953 * mono_unhandled_exception:
3954 * @exc: exception thrown
3956 * This is a VM internal routine.
3958 * We call this function when we detect an unhandled exception
3959 * in the default domain.
3961 * It invokes the * UnhandledException event in AppDomain or prints
3962 * a warning to the console
3965 mono_unhandled_exception (MonoObject *exc)
3967 MonoDomain *current_domain = mono_domain_get ();
3968 MonoDomain *root_domain = mono_get_root_domain ();
3969 MonoClassField *field;
3970 MonoObject *current_appdomain_delegate;
3971 MonoObject *root_appdomain_delegate;
3973 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3974 "UnhandledException");
3977 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3978 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3979 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3980 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3981 if (current_domain != root_domain) {
3982 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3984 current_appdomain_delegate = NULL;
3987 /* set exitcode only if we will abort the process */
3988 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3990 mono_environment_exitcode_set (1);
3991 mono_print_unhandled_exception (exc);
3993 if (root_appdomain_delegate) {
3994 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3996 if (current_appdomain_delegate) {
3997 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4004 * mono_runtime_exec_managed_code:
4005 * @domain: Application domain
4006 * @main_func: function to invoke from the execution thread
4007 * @main_args: parameter to the main_func
4009 * Launch a new thread to execute a function
4011 * main_func is called back from the thread with main_args as the
4012 * parameter. The callback function is expected to start Main()
4013 * eventually. This function then waits for all managed threads to
4015 * It is not necesseray anymore to execute managed code in a subthread,
4016 * so this function should not be used anymore by default: just
4017 * execute the code and then call mono_thread_manage ().
4020 mono_runtime_exec_managed_code (MonoDomain *domain,
4021 MonoMainThreadFunc main_func,
4024 mono_thread_create (domain, main_func, main_args);
4026 mono_thread_manage ();
4030 * Execute a standard Main() method (args doesn't contain the
4034 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4039 MonoCustomAttrInfo* cinfo;
4040 gboolean has_stathread_attribute;
4041 MonoInternalThread* thread = mono_thread_internal_current ();
4047 domain = mono_object_domain (args);
4048 if (!domain->entry_assembly) {
4050 MonoAssembly *assembly;
4052 assembly = method->klass->image->assembly;
4053 domain->entry_assembly = assembly;
4054 /* Domains created from another domain already have application_base and configuration_file set */
4055 if (domain->setup->application_base == NULL) {
4056 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4059 if (domain->setup->configuration_file == NULL) {
4060 str = g_strconcat (assembly->image->name, ".config", NULL);
4061 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4063 mono_set_private_bin_path_from_config (domain);
4067 cinfo = mono_custom_attrs_from_method (method);
4069 static MonoClass *stathread_attribute = NULL;
4070 if (!stathread_attribute)
4071 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4072 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4074 mono_custom_attrs_free (cinfo);
4076 has_stathread_attribute = FALSE;
4078 if (has_stathread_attribute) {
4079 thread->apartment_state = ThreadApartmentState_STA;
4081 thread->apartment_state = ThreadApartmentState_MTA;
4083 mono_thread_init_apartment_state ();
4085 /* FIXME: check signature of method */
4086 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4088 res = mono_runtime_invoke (method, NULL, pa, exc);
4090 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4094 mono_environment_exitcode_set (rval);
4096 mono_runtime_invoke (method, NULL, pa, exc);
4100 /* If the return type of Main is void, only
4101 * set the exitcode if an exception was thrown
4102 * (we don't want to blow away an
4103 * explicitly-set exit code)
4106 mono_environment_exitcode_set (rval);
4114 * mono_install_runtime_invoke:
4115 * @func: Function to install
4117 * This is a VM internal routine
4120 mono_install_runtime_invoke (MonoInvokeFunc func)
4122 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4127 * mono_runtime_invoke_array:
4128 * @method: method to invoke
4129 * @obJ: object instance
4130 * @params: arguments to the method
4131 * @exc: exception information.
4133 * Invokes the method represented by @method on the object @obj.
4135 * obj is the 'this' pointer, it should be NULL for static
4136 * methods, a MonoObject* for object instances and a pointer to
4137 * the value type for value types.
4139 * The params array contains the arguments to the method with the
4140 * same convention: MonoObject* pointers for object instances and
4141 * pointers to the value type otherwise. The _invoke_array
4142 * variant takes a C# object[] as the params argument (MonoArray
4143 * *params): in this case the value types are boxed inside the
4144 * respective reference representation.
4146 * From unmanaged code you'll usually use the
4147 * mono_runtime_invoke() variant.
4149 * Note that this function doesn't handle virtual methods for
4150 * you, it will exec the exact method you pass: we still need to
4151 * expose a function to lookup the derived class implementation
4152 * of a virtual method (there are examples of this in the code,
4155 * You can pass NULL as the exc argument if you don't want to
4156 * catch exceptions, otherwise, *exc will be set to the exception
4157 * thrown, if any. if an exception is thrown, you can't use the
4158 * MonoObject* result from the function.
4160 * If the method returns a value type, it is boxed in an object
4164 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4167 MonoMethodSignature *sig = mono_method_signature (method);
4168 gpointer *pa = NULL;
4171 gboolean has_byref_nullables = FALSE;
4173 if (NULL != params) {
4174 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4175 for (i = 0; i < mono_array_length (params); i++) {
4176 MonoType *t = sig->params [i];
4182 case MONO_TYPE_BOOLEAN:
4185 case MONO_TYPE_CHAR:
4194 case MONO_TYPE_VALUETYPE:
4195 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4196 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4197 pa [i] = mono_array_get (params, MonoObject*, i);
4199 has_byref_nullables = TRUE;
4201 /* MS seems to create the objects if a null is passed in */
4202 if (!mono_array_get (params, MonoObject*, i))
4203 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4207 * We can't pass the unboxed vtype byref to the callee, since
4208 * that would mean the callee would be able to modify boxed
4209 * primitive types. So we (and MS) make a copy of the boxed
4210 * object, pass that to the callee, and replace the original
4211 * boxed object in the arg array with the copy.
4213 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4214 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4215 mono_array_setref (params, i, copy);
4218 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4221 case MONO_TYPE_STRING:
4222 case MONO_TYPE_OBJECT:
4223 case MONO_TYPE_CLASS:
4224 case MONO_TYPE_ARRAY:
4225 case MONO_TYPE_SZARRAY:
4227 pa [i] = mono_array_addr (params, MonoObject*, i);
4228 // FIXME: I need to check this code path
4230 pa [i] = mono_array_get (params, MonoObject*, i);
4232 case MONO_TYPE_GENERICINST:
4234 t = &t->data.generic_class->container_class->this_arg;
4236 t = &t->data.generic_class->container_class->byval_arg;
4238 case MONO_TYPE_PTR: {
4241 /* The argument should be an IntPtr */
4242 arg = mono_array_get (params, MonoObject*, i);
4246 g_assert (arg->vtable->klass == mono_defaults.int_class);
4247 pa [i] = ((MonoIntPtr*)arg)->m_value;
4252 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4257 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4260 if (mono_class_is_nullable (method->klass)) {
4261 /* Need to create a boxed vtype instead */
4267 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4271 obj = mono_object_new (mono_domain_get (), method->klass);
4272 g_assert (obj); /*maybe we should raise a TLE instead?*/
4273 #ifndef DISABLE_REMOTING
4274 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4275 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4278 if (method->klass->valuetype)
4279 o = mono_object_unbox (obj);
4282 } else if (method->klass->valuetype) {
4283 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4286 mono_runtime_invoke (method, o, pa, exc);
4289 if (mono_class_is_nullable (method->klass)) {
4290 MonoObject *nullable;
4292 /* Convert the unboxed vtype into a Nullable structure */
4293 nullable = mono_object_new (mono_domain_get (), method->klass);
4295 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4296 obj = mono_object_unbox (nullable);
4299 /* obj must be already unboxed if needed */
4300 res = mono_runtime_invoke (method, obj, pa, exc);
4302 if (sig->ret->type == MONO_TYPE_PTR) {
4303 MonoClass *pointer_class;
4304 static MonoMethod *box_method;
4306 MonoObject *box_exc;
4309 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4310 * convert it to a Pointer object.
4312 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4314 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4316 g_assert (res->vtable->klass == mono_defaults.int_class);
4317 box_args [0] = ((MonoIntPtr*)res)->m_value;
4318 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4319 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4320 g_assert (!box_exc);
4323 if (has_byref_nullables) {
4325 * The runtime invoke wrapper already converted byref nullables back,
4326 * and stored them in pa, we just need to copy them back to the
4329 for (i = 0; i < mono_array_length (params); i++) {
4330 MonoType *t = sig->params [i];
4332 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4333 mono_array_setref (params, i, pa [i]);
4342 arith_overflow (void)
4344 mono_raise_exception (mono_get_exception_overflow ());
4348 * mono_object_allocate:
4349 * @size: number of bytes to allocate
4351 * This is a very simplistic routine until we have our GC-aware
4354 * Returns: an allocated object of size @size, or NULL on failure.
4356 static inline void *
4357 mono_object_allocate (size_t size, MonoVTable *vtable)
4360 mono_stats.new_object_count++;
4361 ALLOC_OBJECT (o, vtable, size);
4367 * mono_object_allocate_ptrfree:
4368 * @size: number of bytes to allocate
4370 * Note that the memory allocated is not zeroed.
4371 * Returns: an allocated object of size @size, or NULL on failure.
4373 static inline void *
4374 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4377 mono_stats.new_object_count++;
4378 ALLOC_PTRFREE (o, vtable, size);
4382 static inline void *
4383 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4386 ALLOC_TYPED (o, size, vtable);
4387 mono_stats.new_object_count++;
4394 * @klass: the class of the object that we want to create
4396 * Returns: a newly created object whose definition is
4397 * looked up using @klass. This will not invoke any constructors,
4398 * so the consumer of this routine has to invoke any constructors on
4399 * its own to initialize the object.
4401 * It returns NULL on failure.
4404 mono_object_new (MonoDomain *domain, MonoClass *klass)
4408 MONO_ARCH_SAVE_REGS;
4409 vtable = mono_class_vtable (domain, klass);
4412 return mono_object_new_specific (vtable);
4416 * mono_object_new_pinned:
4418 * Same as mono_object_new, but the returned object will be pinned.
4419 * For SGEN, these objects will only be freed at appdomain unload.
4422 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4426 MONO_ARCH_SAVE_REGS;
4427 vtable = mono_class_vtable (domain, klass);
4432 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4434 return mono_object_new_specific (vtable);
4439 * mono_object_new_specific:
4440 * @vtable: the vtable of the object that we want to create
4442 * Returns: A newly created object with class and domain specified
4446 mono_object_new_specific (MonoVTable *vtable)
4450 MONO_ARCH_SAVE_REGS;
4452 /* check for is_com_object for COM Interop */
4453 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4456 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4459 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4462 mono_class_init (klass);
4464 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4466 vtable->domain->create_proxy_for_type_method = im;
4469 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4471 o = mono_runtime_invoke (im, NULL, pa, NULL);
4472 if (o != NULL) return o;
4475 return mono_object_new_alloc_specific (vtable);
4479 mono_object_new_alloc_specific (MonoVTable *vtable)
4483 if (!vtable->klass->has_references) {
4484 o = mono_object_new_ptrfree (vtable);
4485 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4486 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4488 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4489 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4491 if (G_UNLIKELY (vtable->klass->has_finalize))
4492 mono_object_register_finalizer (o);
4494 if (G_UNLIKELY (profile_allocs))
4495 mono_profiler_allocation (o, vtable->klass);
4500 mono_object_new_fast (MonoVTable *vtable)
4503 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4508 mono_object_new_ptrfree (MonoVTable *vtable)
4511 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4512 #if NEED_TO_ZERO_PTRFREE
4513 /* an inline memset is much faster for the common vcase of small objects
4514 * note we assume the allocated size is a multiple of sizeof (void*).
4516 if (vtable->klass->instance_size < 128) {
4518 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4519 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4525 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4532 mono_object_new_ptrfree_box (MonoVTable *vtable)
4535 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4536 /* the object will be boxed right away, no need to memzero it */
4541 * mono_class_get_allocation_ftn:
4543 * @for_box: the object will be used for boxing
4544 * @pass_size_in_words:
4546 * Return the allocation function appropriate for the given class.
4550 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4552 *pass_size_in_words = FALSE;
4554 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4555 profile_allocs = FALSE;
4557 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4558 return mono_object_new_specific;
4560 if (!vtable->klass->has_references) {
4561 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4563 return mono_object_new_ptrfree_box;
4564 return mono_object_new_ptrfree;
4567 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4569 return mono_object_new_fast;
4572 * FIXME: This is actually slower than mono_object_new_fast, because
4573 * of the overhead of parameter passing.
4576 *pass_size_in_words = TRUE;
4577 #ifdef GC_REDIRECT_TO_LOCAL
4578 return GC_local_gcj_fast_malloc;
4580 return GC_gcj_fast_malloc;
4585 return mono_object_new_specific;
4589 * mono_object_new_from_token:
4590 * @image: Context where the type_token is hosted
4591 * @token: a token of the type that we want to create
4593 * Returns: A newly created object whose definition is
4594 * looked up using @token in the @image image
4597 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4601 class = mono_class_get (image, token);
4603 return mono_object_new (domain, class);
4608 * mono_object_clone:
4609 * @obj: the object to clone
4611 * Returns: A newly created object who is a shallow copy of @obj
4614 mono_object_clone (MonoObject *obj)
4617 int size = obj->vtable->klass->instance_size;
4619 if (obj->vtable->klass->rank)
4620 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4622 o = mono_object_allocate (size, obj->vtable);
4624 if (obj->vtable->klass->has_references) {
4625 mono_gc_wbarrier_object_copy (o, obj);
4627 int size = obj->vtable->klass->instance_size;
4628 /* do not copy the sync state */
4629 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4631 if (G_UNLIKELY (profile_allocs))
4632 mono_profiler_allocation (o, obj->vtable->klass);
4634 if (obj->vtable->klass->has_finalize)
4635 mono_object_register_finalizer (o);
4640 * mono_array_full_copy:
4641 * @src: source array to copy
4642 * @dest: destination array
4644 * Copies the content of one array to another with exactly the same type and size.
4647 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4650 MonoClass *klass = src->obj.vtable->klass;
4652 MONO_ARCH_SAVE_REGS;
4654 g_assert (klass == dest->obj.vtable->klass);
4656 size = mono_array_length (src);
4657 g_assert (size == mono_array_length (dest));
4658 size *= mono_array_element_size (klass);
4660 if (klass->element_class->valuetype) {
4661 if (klass->element_class->has_references)
4662 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4664 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4666 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4669 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4674 * mono_array_clone_in_domain:
4675 * @domain: the domain in which the array will be cloned into
4676 * @array: the array to clone
4678 * This routine returns a copy of the array that is hosted on the
4679 * specified MonoDomain.
4682 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4687 MonoClass *klass = array->obj.vtable->klass;
4689 MONO_ARCH_SAVE_REGS;
4691 if (array->bounds == NULL) {
4692 size = mono_array_length (array);
4693 o = mono_array_new_full (domain, klass, &size, NULL);
4695 size *= mono_array_element_size (klass);
4697 if (klass->element_class->valuetype) {
4698 if (klass->element_class->has_references)
4699 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4701 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4703 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4706 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4711 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4712 size = mono_array_element_size (klass);
4713 for (i = 0; i < klass->rank; ++i) {
4714 sizes [i] = array->bounds [i].length;
4715 size *= array->bounds [i].length;
4716 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4718 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4720 if (klass->element_class->valuetype) {
4721 if (klass->element_class->has_references)
4722 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4724 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4726 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4729 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4737 * @array: the array to clone
4739 * Returns: A newly created array who is a shallow copy of @array
4742 mono_array_clone (MonoArray *array)
4744 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4747 /* helper macros to check for overflow when calculating the size of arrays */
4748 #ifdef MONO_BIG_ARRAYS
4749 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4750 #define MYGUINT_MAX MYGUINT64_MAX
4751 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4752 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4753 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4754 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4755 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4757 #define MYGUINT32_MAX 4294967295U
4758 #define MYGUINT_MAX MYGUINT32_MAX
4759 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4760 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4761 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4762 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4763 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4767 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4771 byte_len = mono_array_element_size (class);
4772 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4775 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4777 byte_len += sizeof (MonoArray);
4785 * mono_array_new_full:
4786 * @domain: domain where the object is created
4787 * @array_class: array class
4788 * @lengths: lengths for each dimension in the array
4789 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4791 * This routine creates a new array objects with the given dimensions,
4792 * lower bounds and type.
4795 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4797 uintptr_t byte_len = 0, len, bounds_size;
4800 MonoArrayBounds *bounds;
4804 if (!array_class->inited)
4805 mono_class_init (array_class);
4809 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4810 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4812 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4816 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4818 for (i = 0; i < array_class->rank; ++i) {
4819 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4821 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4822 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4827 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4828 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4832 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4833 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4834 byte_len = (byte_len + 3) & ~3;
4835 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4836 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4837 byte_len += bounds_size;
4840 * Following three lines almost taken from mono_object_new ():
4841 * they need to be kept in sync.
4843 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4844 #ifndef HAVE_SGEN_GC
4845 if (!array_class->has_references) {
4846 o = mono_object_allocate_ptrfree (byte_len, vtable);
4847 #if NEED_TO_ZERO_PTRFREE
4848 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4850 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4851 o = mono_object_allocate_spec (byte_len, vtable);
4853 o = mono_object_allocate (byte_len, vtable);
4856 array = (MonoArray*)o;
4857 array->max_length = len;
4860 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4861 array->bounds = bounds;
4865 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4867 o = mono_gc_alloc_vector (vtable, byte_len, len);
4868 array = (MonoArray*)o;
4869 mono_stats.new_object_count++;
4871 bounds = array->bounds;
4875 for (i = 0; i < array_class->rank; ++i) {
4876 bounds [i].length = lengths [i];
4878 bounds [i].lower_bound = lower_bounds [i];
4882 if (G_UNLIKELY (profile_allocs))
4883 mono_profiler_allocation (o, array_class);
4890 * @domain: domain where the object is created
4891 * @eclass: element class
4892 * @n: number of array elements
4894 * This routine creates a new szarray with @n elements of type @eclass.
4897 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4901 MONO_ARCH_SAVE_REGS;
4903 ac = mono_array_class_get (eclass, 1);
4906 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4910 * mono_array_new_specific:
4911 * @vtable: a vtable in the appropriate domain for an initialized class
4912 * @n: number of array elements
4914 * This routine is a fast alternative to mono_array_new() for code which
4915 * can be sure about the domain it operates in.
4918 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4924 MONO_ARCH_SAVE_REGS;
4926 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4931 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4932 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4935 #ifndef HAVE_SGEN_GC
4936 if (!vtable->klass->has_references) {
4937 o = mono_object_allocate_ptrfree (byte_len, vtable);
4938 #if NEED_TO_ZERO_PTRFREE
4939 ((MonoArray*)o)->bounds = NULL;
4940 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4942 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4943 o = mono_object_allocate_spec (byte_len, vtable);
4945 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4946 o = mono_object_allocate (byte_len, vtable);
4949 ao = (MonoArray *)o;
4952 o = mono_gc_alloc_vector (vtable, byte_len, n);
4954 mono_stats.new_object_count++;
4957 if (G_UNLIKELY (profile_allocs))
4958 mono_profiler_allocation (o, vtable->klass);
4964 * mono_string_new_utf16:
4965 * @text: a pointer to an utf16 string
4966 * @len: the length of the string
4968 * Returns: A newly created string object which contains @text.
4971 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4975 s = mono_string_new_size (domain, len);
4976 g_assert (s != NULL);
4978 memcpy (mono_string_chars (s), text, len * 2);
4984 * mono_string_new_size:
4985 * @text: a pointer to an utf16 string
4986 * @len: the length of the string
4988 * Returns: A newly created string object of @len
4991 mono_string_new_size (MonoDomain *domain, gint32 len)
4997 /* check for overflow */
4998 if (len < 0 || len > ((SIZE_MAX - sizeof (MonoString) - 2) / 2))
4999 mono_gc_out_of_memory (-1);
5001 size = (sizeof (MonoString) + ((len + 1) * 2));
5002 g_assert (size > 0);
5004 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5007 #ifndef HAVE_SGEN_GC
5008 s = mono_object_allocate_ptrfree (size, vtable);
5012 s = mono_gc_alloc_string (vtable, size, len);
5014 #if NEED_TO_ZERO_PTRFREE
5017 if (G_UNLIKELY (profile_allocs))
5018 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5024 * mono_string_new_len:
5025 * @text: a pointer to an utf8 string
5026 * @length: number of bytes in @text to consider
5028 * Returns: A newly created string object which contains @text.
5031 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5033 GError *error = NULL;
5034 MonoString *o = NULL;
5036 glong items_written;
5038 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5041 o = mono_string_new_utf16 (domain, ut, items_written);
5043 g_error_free (error);
5052 * @text: a pointer to an utf8 string
5054 * Returns: A newly created string object which contains @text.
5057 mono_string_new (MonoDomain *domain, const char *text)
5059 GError *error = NULL;
5060 MonoString *o = NULL;
5062 glong items_written;
5067 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5070 o = mono_string_new_utf16 (domain, ut, items_written);
5072 g_error_free (error);
5075 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5080 MonoString *o = NULL;
5082 if (!g_utf8_validate (text, -1, &end))
5085 len = g_utf8_strlen (text, -1);
5086 o = mono_string_new_size (domain, len);
5087 str = mono_string_chars (o);
5089 while (text < end) {
5090 *str++ = g_utf8_get_char (text);
5091 text = g_utf8_next_char (text);
5098 * mono_string_new_wrapper:
5099 * @text: pointer to utf8 characters.
5101 * Helper function to create a string object from @text in the current domain.
5104 mono_string_new_wrapper (const char *text)
5106 MonoDomain *domain = mono_domain_get ();
5108 MONO_ARCH_SAVE_REGS;
5111 return mono_string_new (domain, text);
5118 * @class: the class of the value
5119 * @value: a pointer to the unboxed data
5121 * Returns: A newly created object which contains @value.
5124 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5130 g_assert (class->valuetype);
5131 if (mono_class_is_nullable (class))
5132 return mono_nullable_box (value, class);
5134 vtable = mono_class_vtable (domain, class);
5137 size = mono_class_instance_size (class);
5138 res = mono_object_new_alloc_specific (vtable);
5139 if (G_UNLIKELY (profile_allocs))
5140 mono_profiler_allocation (res, class);
5142 size = size - sizeof (MonoObject);
5145 g_assert (size == mono_class_value_size (class, NULL));
5146 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5148 #if NO_UNALIGNED_ACCESS
5149 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5153 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5156 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5159 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5162 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5165 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5169 if (class->has_finalize)
5170 mono_object_register_finalizer (res);
5176 * @dest: destination pointer
5177 * @src: source pointer
5178 * @klass: a valuetype class
5180 * Copy a valuetype from @src to @dest. This function must be used
5181 * when @klass contains references fields.
5184 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5186 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5190 * mono_value_copy_array:
5191 * @dest: destination array
5192 * @dest_idx: index in the @dest array
5193 * @src: source pointer
5194 * @count: number of items
5196 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5197 * This function must be used when @klass contains references fields.
5198 * Overlap is handled.
5201 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5203 int size = mono_array_element_size (dest->obj.vtable->klass);
5204 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5205 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5206 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5210 * mono_object_get_domain:
5211 * @obj: object to query
5213 * Returns: the MonoDomain where the object is hosted
5216 mono_object_get_domain (MonoObject *obj)
5218 return mono_object_domain (obj);
5222 * mono_object_get_class:
5223 * @obj: object to query
5225 * Returns: the MonOClass of the object.
5228 mono_object_get_class (MonoObject *obj)
5230 return mono_object_class (obj);
5233 * mono_object_get_size:
5234 * @o: object to query
5236 * Returns: the size, in bytes, of @o
5239 mono_object_get_size (MonoObject* o)
5241 MonoClass* klass = mono_object_class (o);
5242 if (klass == mono_defaults.string_class) {
5243 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5244 } else if (o->vtable->rank) {
5245 MonoArray *array = (MonoArray*)o;
5246 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5247 if (array->bounds) {
5250 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5254 return mono_class_instance_size (klass);
5259 * mono_object_unbox:
5260 * @obj: object to unbox
5262 * Returns: a pointer to the start of the valuetype boxed in this
5265 * This method will assert if the object passed is not a valuetype.
5268 mono_object_unbox (MonoObject *obj)
5270 /* add assert for valuetypes? */
5271 g_assert (obj->vtable->klass->valuetype);
5272 return ((char*)obj) + sizeof (MonoObject);
5276 * mono_object_isinst:
5278 * @klass: a pointer to a class
5280 * Returns: @obj if @obj is derived from @klass
5283 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5286 mono_class_init (klass);
5288 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5289 return mono_object_isinst_mbyref (obj, klass);
5294 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5298 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5307 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5308 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5312 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5313 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5316 MonoClass *oklass = vt->klass;
5317 if (mono_class_is_transparent_proxy (oklass))
5318 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5320 mono_class_setup_supertypes (klass);
5321 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5324 #ifndef DISABLE_REMOTING
5325 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5327 MonoDomain *domain = mono_domain_get ();
5329 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5330 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5331 MonoMethod *im = NULL;
5334 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5335 im = mono_object_get_virtual_method (rp, im);
5338 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5341 res = mono_runtime_invoke (im, rp, pa, NULL);
5343 if (*(MonoBoolean *) mono_object_unbox(res)) {
5344 /* Update the vtable of the remote type, so it can safely cast to this new type */
5345 mono_upgrade_remote_class (domain, obj, klass);
5349 #endif /* DISABLE_REMOTING */
5354 * mono_object_castclass_mbyref:
5356 * @klass: a pointer to a class
5358 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5361 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5363 if (!obj) return NULL;
5364 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5366 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5368 "InvalidCastException"));
5373 MonoDomain *orig_domain;
5379 str_lookup (MonoDomain *domain, gpointer user_data)
5381 LDStrInfo *info = user_data;
5382 if (info->res || domain == info->orig_domain)
5384 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5390 mono_string_get_pinned (MonoString *str)
5394 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5395 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5397 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5398 news->length = mono_string_length (str);
5404 #define mono_string_get_pinned(str) (str)
5408 mono_string_is_interned_lookup (MonoString *str, int insert)
5410 MonoGHashTable *ldstr_table;
5414 domain = ((MonoObject *)str)->vtable->domain;
5415 ldstr_table = domain->ldstr_table;
5417 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5422 str = mono_string_get_pinned (str);
5424 mono_g_hash_table_insert (ldstr_table, str, str);
5428 LDStrInfo ldstr_info;
5429 ldstr_info.orig_domain = domain;
5430 ldstr_info.ins = str;
5431 ldstr_info.res = NULL;
5433 mono_domain_foreach (str_lookup, &ldstr_info);
5434 if (ldstr_info.res) {
5436 * the string was already interned in some other domain:
5437 * intern it in the current one as well.
5439 mono_g_hash_table_insert (ldstr_table, str, str);
5449 * mono_string_is_interned:
5450 * @o: String to probe
5452 * Returns whether the string has been interned.
5455 mono_string_is_interned (MonoString *o)
5457 return mono_string_is_interned_lookup (o, FALSE);
5461 * mono_string_intern:
5462 * @o: String to intern
5464 * Interns the string passed.
5465 * Returns: The interned string.
5468 mono_string_intern (MonoString *str)
5470 return mono_string_is_interned_lookup (str, TRUE);
5475 * @domain: the domain where the string will be used.
5476 * @image: a metadata context
5477 * @idx: index into the user string table.
5479 * Implementation for the ldstr opcode.
5480 * Returns: a loaded string from the @image/@idx combination.
5483 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5485 MONO_ARCH_SAVE_REGS;
5487 if (image->dynamic) {
5488 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5491 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5492 return NULL; /*FIXME we should probably be raising an exception here*/
5493 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5498 * mono_ldstr_metadata_sig
5499 * @domain: the domain for the string
5500 * @sig: the signature of a metadata string
5502 * Returns: a MonoString for a string stored in the metadata
5505 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5507 const char *str = sig;
5508 MonoString *o, *interned;
5511 len2 = mono_metadata_decode_blob_size (str, &str);
5514 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5515 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5518 guint16 *p2 = (guint16*)mono_string_chars (o);
5519 for (i = 0; i < len2; ++i) {
5520 *p2 = GUINT16_FROM_LE (*p2);
5526 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5528 /* o will get garbage collected */
5532 o = mono_string_get_pinned (o);
5534 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5541 * mono_string_to_utf8:
5542 * @s: a System.String
5544 * Returns the UTF8 representation for @s.
5545 * The resulting buffer needs to be freed with mono_free().
5547 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5550 mono_string_to_utf8 (MonoString *s)
5553 char *result = mono_string_to_utf8_checked (s, &error);
5555 if (!mono_error_ok (&error))
5556 mono_error_raise_exception (&error);
5561 * mono_string_to_utf8_checked:
5562 * @s: a System.String
5563 * @error: a MonoError.
5565 * Converts a MonoString to its UTF8 representation. May fail; check
5566 * @error to determine whether the conversion was successful.
5567 * The resulting buffer should be freed with mono_free().
5570 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5574 GError *gerror = NULL;
5576 mono_error_init (error);
5582 return g_strdup ("");
5584 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5586 mono_error_set_argument (error, "string", "%s", gerror->message);
5587 g_error_free (gerror);
5590 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5591 if (s->length > written) {
5592 /* allocate the total length and copy the part of the string that has been converted */
5593 char *as2 = g_malloc0 (s->length);
5594 memcpy (as2, as, written);
5603 * mono_string_to_utf8_ignore:
5606 * Converts a MonoString to its UTF8 representation. Will ignore
5607 * invalid surrogate pairs.
5608 * The resulting buffer should be freed with mono_free().
5612 mono_string_to_utf8_ignore (MonoString *s)
5621 return g_strdup ("");
5623 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5625 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5626 if (s->length > written) {
5627 /* allocate the total length and copy the part of the string that has been converted */
5628 char *as2 = g_malloc0 (s->length);
5629 memcpy (as2, as, written);
5638 * mono_string_to_utf8_image_ignore:
5639 * @s: a System.String
5641 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5644 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5646 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5650 * mono_string_to_utf8_mp_ignore:
5651 * @s: a System.String
5653 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5656 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5658 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5663 * mono_string_to_utf16:
5666 * Return an null-terminated array of the utf-16 chars
5667 * contained in @s. The result must be freed with g_free().
5668 * This is a temporary helper until our string implementation
5669 * is reworked to always include the null terminating char.
5672 mono_string_to_utf16 (MonoString *s)
5679 as = g_malloc ((s->length * 2) + 2);
5680 as [(s->length * 2)] = '\0';
5681 as [(s->length * 2) + 1] = '\0';
5684 return (gunichar2 *)(as);
5687 memcpy (as, mono_string_chars(s), s->length * 2);
5688 return (gunichar2 *)(as);
5692 * mono_string_from_utf16:
5693 * @data: the UTF16 string (LPWSTR) to convert
5695 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5697 * Returns: a MonoString.
5700 mono_string_from_utf16 (gunichar2 *data)
5702 MonoDomain *domain = mono_domain_get ();
5708 while (data [len]) len++;
5710 return mono_string_new_utf16 (domain, data, len);
5715 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5722 r = mono_string_to_utf8_ignore (s);
5724 r = mono_string_to_utf8_checked (s, error);
5725 if (!mono_error_ok (error))
5732 len = strlen (r) + 1;
5734 mp_s = mono_mempool_alloc (mp, len);
5736 mp_s = mono_image_alloc (image, len);
5738 memcpy (mp_s, r, len);
5746 * mono_string_to_utf8_image:
5747 * @s: a System.String
5749 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5752 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5754 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5758 * mono_string_to_utf8_mp:
5759 * @s: a System.String
5761 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5764 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5766 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5770 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5773 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5775 eh_callbacks = *cbs;
5778 MonoRuntimeExceptionHandlingCallbacks *
5779 mono_get_eh_callbacks (void)
5781 return &eh_callbacks;
5785 * mono_raise_exception:
5786 * @ex: exception object
5788 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5791 mono_raise_exception (MonoException *ex)
5794 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5795 * that will cause gcc to omit the function epilog, causing problems when
5796 * the JIT tries to walk the stack, since the return address on the stack
5797 * will point into the next function in the executable, not this one.
5799 eh_callbacks.mono_raise_exception (ex);
5803 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5805 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5809 * mono_wait_handle_new:
5810 * @domain: Domain where the object will be created
5811 * @handle: Handle for the wait handle
5813 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5816 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5818 MonoWaitHandle *res;
5819 gpointer params [1];
5820 static MonoMethod *handle_set;
5822 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5824 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5826 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5828 params [0] = &handle;
5829 mono_runtime_invoke (handle_set, res, params, NULL);
5835 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5837 static MonoClassField *f_os_handle;
5838 static MonoClassField *f_safe_handle;
5840 if (!f_os_handle && !f_safe_handle) {
5841 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5842 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5847 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5851 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5858 mono_runtime_capture_context (MonoDomain *domain)
5860 RuntimeInvokeFunction runtime_invoke;
5862 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5863 MonoMethod *method = mono_get_context_capture_method ();
5864 MonoMethod *wrapper;
5867 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5868 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5869 domain->capture_context_method = mono_compile_method (method);
5872 runtime_invoke = domain->capture_context_runtime_invoke;
5874 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5877 * mono_async_result_new:
5878 * @domain:domain where the object will be created.
5879 * @handle: wait handle.
5880 * @state: state to pass to AsyncResult
5881 * @data: C closure data.
5883 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5884 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5888 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5890 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5891 MonoObject *context = mono_runtime_capture_context (domain);
5892 /* we must capture the execution context from the original thread */
5894 MONO_OBJECT_SETREF (res, execution_context, context);
5895 /* note: result may be null if the flow is suppressed */
5899 MONO_OBJECT_SETREF (res, object_data, object_data);
5900 MONO_OBJECT_SETREF (res, async_state, state);
5902 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5904 res->sync_completed = FALSE;
5905 res->completed = FALSE;
5911 mono_message_init (MonoDomain *domain,
5912 MonoMethodMessage *this,
5913 MonoReflectionMethod *method,
5914 MonoArray *out_args)
5916 static MonoClass *object_array_klass;
5917 static MonoClass *byte_array_klass;
5918 static MonoClass *string_array_klass;
5919 MonoMethodSignature *sig = mono_method_signature (method->method);
5925 if (!object_array_klass) {
5928 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5930 byte_array_klass = klass;
5932 klass = mono_array_class_get (mono_defaults.string_class, 1);
5934 string_array_klass = klass;
5936 klass = mono_array_class_get (mono_defaults.object_class, 1);
5939 mono_atomic_store_release (&object_array_klass, klass);
5942 MONO_OBJECT_SETREF (this, method, method);
5944 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5945 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5946 this->async_result = NULL;
5947 this->call_type = CallType_Sync;
5949 names = g_new (char *, sig->param_count);
5950 mono_method_get_param_names (method->method, (const char **) names);
5951 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5953 for (i = 0; i < sig->param_count; i++) {
5954 name = mono_string_new (domain, names [i]);
5955 mono_array_setref (this->names, i, name);
5959 for (i = 0, j = 0; i < sig->param_count; i++) {
5960 if (sig->params [i]->byref) {
5962 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5963 mono_array_setref (this->args, i, arg);
5967 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5971 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5974 mono_array_set (this->arg_types, guint8, i, arg_type);
5978 #ifndef DISABLE_REMOTING
5980 * mono_remoting_invoke:
5981 * @real_proxy: pointer to a RealProxy object
5982 * @msg: The MonoMethodMessage to execute
5983 * @exc: used to store exceptions
5984 * @out_args: used to store output arguments
5986 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5987 * IMessage interface and it is not trivial to extract results from there. So
5988 * we call an helper method PrivateInvoke instead of calling
5989 * RealProxy::Invoke() directly.
5991 * Returns: the result object.
5994 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5995 MonoObject **exc, MonoArray **out_args)
5997 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6000 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6003 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6005 real_proxy->vtable->domain->private_invoke_method = im;
6008 pa [0] = real_proxy;
6013 return mono_runtime_invoke (im, NULL, pa, exc);
6018 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6019 MonoObject **exc, MonoArray **out_args)
6021 static MonoClass *object_array_klass;
6024 MonoMethodSignature *sig;
6026 int i, j, outarg_count = 0;
6028 #ifndef DISABLE_REMOTING
6029 if (target && mono_object_is_transparent_proxy (target)) {
6030 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6031 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6032 target = tp->rp->unwrapped_server;
6034 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6039 domain = mono_domain_get ();
6040 method = msg->method->method;
6041 sig = mono_method_signature (method);
6043 for (i = 0; i < sig->param_count; i++) {
6044 if (sig->params [i]->byref)
6048 if (!object_array_klass) {
6051 klass = mono_array_class_get (mono_defaults.object_class, 1);
6054 mono_memory_barrier ();
6055 object_array_klass = klass;
6058 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6059 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6062 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6064 for (i = 0, j = 0; i < sig->param_count; i++) {
6065 if (sig->params [i]->byref) {
6067 arg = mono_array_get (msg->args, gpointer, i);
6068 mono_array_setref (*out_args, j, arg);
6077 * mono_object_to_string:
6079 * @exc: Any exception thrown by ToString (). May be NULL.
6081 * Returns: the result of calling ToString () on an object.
6084 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6086 static MonoMethod *to_string = NULL;
6093 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6095 method = mono_object_get_virtual_method (obj, to_string);
6097 // Unbox value type if needed
6098 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6099 target = mono_object_unbox (obj);
6102 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6106 * mono_print_unhandled_exception:
6107 * @exc: The exception
6109 * Prints the unhandled exception.
6112 mono_print_unhandled_exception (MonoObject *exc)
6115 char *message = (char*)"";
6116 gboolean free_message = FALSE;
6119 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6120 message = g_strdup ("OutOfMemoryException");
6121 free_message = TRUE;
6124 if (((MonoException*)exc)->native_trace_ips) {
6125 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6126 free_message = TRUE;
6128 MonoObject *other_exc = NULL;
6129 str = mono_object_to_string (exc, &other_exc);
6131 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6132 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6134 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6135 original_backtrace, nested_backtrace);
6137 g_free (original_backtrace);
6138 g_free (nested_backtrace);
6139 free_message = TRUE;
6141 message = mono_string_to_utf8_checked (str, &error);
6142 if (!mono_error_ok (&error)) {
6143 mono_error_cleanup (&error);
6144 message = (char *) "";
6146 free_message = TRUE;
6153 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6154 * exc->vtable->klass->name, message);
6156 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6163 * mono_delegate_ctor:
6164 * @this: pointer to an uninitialized delegate object
6165 * @target: target object
6166 * @addr: pointer to native code
6169 * Initialize a delegate and sets a specific method, not the one
6170 * associated with addr. This is useful when sharing generic code.
6171 * In that case addr will most probably not be associated with the
6172 * correct instantiation of the method.
6175 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6177 MonoDelegate *delegate = (MonoDelegate *)this;
6184 delegate->method = method;
6186 class = this->vtable->klass;
6187 mono_stats.delegate_creations++;
6189 #ifndef DISABLE_REMOTING
6190 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6192 method = mono_marshal_get_remoting_invoke (method);
6193 delegate->method_ptr = mono_compile_method (method);
6194 MONO_OBJECT_SETREF (delegate, target, target);
6198 delegate->method_ptr = addr;
6199 MONO_OBJECT_SETREF (delegate, target, target);
6202 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6206 * mono_delegate_ctor:
6207 * @this: pointer to an uninitialized delegate object
6208 * @target: target object
6209 * @addr: pointer to native code
6211 * This is used to initialize a delegate.
6214 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6216 MonoDomain *domain = mono_domain_get ();
6218 MonoMethod *method = NULL;
6222 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6224 if (!ji && domain != mono_get_root_domain ())
6225 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6227 method = mono_jit_info_get_method (ji);
6228 g_assert (!method->klass->generic_container);
6231 mono_delegate_ctor_with_method (this, target, addr, method);
6235 * mono_method_call_message_new:
6236 * @method: method to encapsulate
6237 * @params: parameters to the method
6238 * @invoke: optional, delegate invoke.
6239 * @cb: async callback delegate.
6240 * @state: state passed to the async callback.
6242 * Translates arguments pointers into a MonoMethodMessage.
6245 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6246 MonoDelegate **cb, MonoObject **state)
6248 MonoDomain *domain = mono_domain_get ();
6249 MonoMethodSignature *sig = mono_method_signature (method);
6250 MonoMethodMessage *msg;
6253 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6256 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6257 count = sig->param_count - 2;
6259 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6260 count = sig->param_count;
6263 for (i = 0; i < count; i++) {
6268 if (sig->params [i]->byref)
6269 vpos = *((gpointer *)params [i]);
6273 type = sig->params [i]->type;
6274 class = mono_class_from_mono_type (sig->params [i]);
6276 if (class->valuetype)
6277 arg = mono_value_box (domain, class, vpos);
6279 arg = *((MonoObject **)vpos);
6281 mono_array_setref (msg->args, i, arg);
6284 if (cb != NULL && state != NULL) {
6285 *cb = *((MonoDelegate **)params [i]);
6287 *state = *((MonoObject **)params [i]);
6294 * mono_method_return_message_restore:
6296 * Restore results from message based processing back to arguments pointers
6299 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6301 MonoMethodSignature *sig = mono_method_signature (method);
6302 int i, j, type, size, out_len;
6304 if (out_args == NULL)
6306 out_len = mono_array_length (out_args);
6310 for (i = 0, j = 0; i < sig->param_count; i++) {
6311 MonoType *pt = sig->params [i];
6316 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6318 arg = mono_array_get (out_args, gpointer, j);
6321 g_assert (type != MONO_TYPE_VOID);
6323 if (MONO_TYPE_IS_REFERENCE (pt)) {
6324 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6327 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6328 size = mono_class_value_size (class, NULL);
6329 if (class->has_references)
6330 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6332 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6334 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6335 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6344 #ifndef DISABLE_REMOTING
6347 * mono_load_remote_field:
6348 * @this: pointer to an object
6349 * @klass: klass of the object containing @field
6350 * @field: the field to load
6351 * @res: a storage to store the result
6353 * This method is called by the runtime on attempts to load fields of
6354 * transparent proxy objects. @this points to such TP, @klass is the class of
6355 * the object containing @field. @res is a storage location which can be
6356 * used to store the result.
6358 * Returns: an address pointing to the value of field.
6361 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6363 static MonoMethod *getter = NULL;
6364 MonoDomain *domain = mono_domain_get ();
6365 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6366 MonoClass *field_class;
6367 MonoMethodMessage *msg;
6368 MonoArray *out_args;
6372 g_assert (mono_object_is_transparent_proxy (this));
6373 g_assert (res != NULL);
6375 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6376 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6381 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6385 field_class = mono_class_from_mono_type (field->type);
6387 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6388 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6389 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6391 full_name = mono_type_get_full_name (klass);
6392 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6393 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6396 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6398 if (exc) mono_raise_exception ((MonoException *)exc);
6400 if (mono_array_length (out_args) == 0)
6403 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6405 if (field_class->valuetype) {
6406 return ((char *)*res) + sizeof (MonoObject);
6412 * mono_load_remote_field_new:
6417 * Missing documentation.
6420 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6422 static MonoMethod *getter = NULL;
6423 MonoDomain *domain = mono_domain_get ();
6424 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6425 MonoClass *field_class;
6426 MonoMethodMessage *msg;
6427 MonoArray *out_args;
6428 MonoObject *exc, *res;
6431 g_assert (mono_object_is_transparent_proxy (this));
6433 field_class = mono_class_from_mono_type (field->type);
6435 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6437 if (field_class->valuetype) {
6438 res = mono_object_new (domain, field_class);
6439 val = ((gchar *) res) + sizeof (MonoObject);
6443 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6448 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6452 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6453 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6455 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
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)));
6462 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6464 if (exc) mono_raise_exception ((MonoException *)exc);
6466 if (mono_array_length (out_args) == 0)
6469 res = mono_array_get (out_args, MonoObject *, 0);
6475 * mono_store_remote_field:
6476 * @this: pointer to an object
6477 * @klass: klass of the object containing @field
6478 * @field: the field to load
6479 * @val: the value/object to store
6481 * This method is called by the runtime on attempts to store fields of
6482 * transparent proxy objects. @this points to such TP, @klass is the class of
6483 * the object containing @field. @val is the new value to store in @field.
6486 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6488 static MonoMethod *setter = NULL;
6489 MonoDomain *domain = mono_domain_get ();
6490 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6491 MonoClass *field_class;
6492 MonoMethodMessage *msg;
6493 MonoArray *out_args;
6498 g_assert (mono_object_is_transparent_proxy (this));
6500 field_class = mono_class_from_mono_type (field->type);
6502 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6503 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6504 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6509 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6513 if (field_class->valuetype)
6514 arg = mono_value_box (domain, field_class, val);
6516 arg = *((MonoObject **)val);
6519 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6520 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6522 full_name = mono_type_get_full_name (klass);
6523 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6524 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6525 mono_array_setref (msg->args, 2, arg);
6528 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6530 if (exc) mono_raise_exception ((MonoException *)exc);
6534 * mono_store_remote_field_new:
6540 * Missing documentation
6543 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6545 static MonoMethod *setter = NULL;
6546 MonoDomain *domain = mono_domain_get ();
6547 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6548 MonoClass *field_class;
6549 MonoMethodMessage *msg;
6550 MonoArray *out_args;
6554 g_assert (mono_object_is_transparent_proxy (this));
6556 field_class = mono_class_from_mono_type (field->type);
6558 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6559 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6560 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6565 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6569 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6570 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6572 full_name = mono_type_get_full_name (klass);
6573 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6574 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6575 mono_array_setref (msg->args, 2, arg);
6578 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6580 if (exc) mono_raise_exception ((MonoException *)exc);
6585 * mono_create_ftnptr:
6587 * Given a function address, create a function descriptor for it.
6588 * This is only needed on some platforms.
6591 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6593 return callbacks.create_ftnptr (domain, addr);
6597 * mono_get_addr_from_ftnptr:
6599 * Given a pointer to a function descriptor, return the function address.
6600 * This is only needed on some platforms.
6603 mono_get_addr_from_ftnptr (gpointer descr)
6605 return callbacks.get_addr_from_ftnptr (descr);
6609 * mono_string_chars:
6612 * Returns a pointer to the UCS16 characters stored in the MonoString
6615 mono_string_chars (MonoString *s)
6621 * mono_string_length:
6624 * Returns the lenght in characters of the string
6627 mono_string_length (MonoString *s)
6633 * mono_array_length:
6634 * @array: a MonoArray*
6636 * Returns the total number of elements in the array. This works for
6637 * both vectors and multidimensional arrays.
6640 mono_array_length (MonoArray *array)
6642 return array->max_length;
6646 * mono_array_addr_with_size:
6647 * @array: a MonoArray*
6648 * @size: size of the array elements
6649 * @idx: index into the array
6651 * Returns the address of the @idx element in the array.
6654 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6656 return ((char*)(array)->vector) + size * idx;