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() EnterCriticalSection (&ldstr_section)
92 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
93 static CRITICAL_SECTION 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 CRITICAL_SECTION initialization_section;
141 } TypeInitializationLock;
143 /* for locking access to type_initialization_hash and blocked_thread_hash */
144 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
145 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
146 static CRITICAL_SECTION 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 InitializeCriticalSection (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 InitializeCriticalSection (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 DeleteCriticalSection (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 DeleteCriticalSection (&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 InitializeCriticalSection (&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 EnterCriticalSection (&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 LeaveCriticalSection (&lock->initialization_section);
409 /* this just blocks until the initializing thread is done */
410 EnterCriticalSection (&lock->initialization_section);
411 LeaveCriticalSection (&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 DeleteCriticalSection (&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 LeaveCriticalSection (&lock->initialization_section);
456 --lock->waiting_count;
457 if (lock->waiting_count == 0) {
458 DeleteCriticalSection (&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);
1353 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1355 interface_offset += iface->method.count;
1358 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1359 /* overwrite the imt slot only if we're building all the entries or if
1360 * we're building this specific one
1362 if (slot_num < 0 || i == slot_num) {
1363 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1366 if (imt_builder [i]) {
1367 MonoImtBuilderEntry *entry;
1369 /* Link entries with imt_builder [i] */
1370 for (entry = entries; entry->next; entry = entry->next) {
1372 MonoMethod *method = (MonoMethod*)entry->key;
1373 char *method_name = mono_method_full_name (method, TRUE);
1374 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1375 g_free (method_name);
1378 entry->next = imt_builder [i];
1379 entries->children += imt_builder [i]->children + 1;
1381 imt_builder [i] = entries;
1384 if (has_generic_virtual || has_variant_iface) {
1386 * There might be collisions later when the the thunk is expanded.
1388 imt_collisions_bitmap |= (1 << i);
1391 * The IMT thunk might be called with an instance of one of the
1392 * generic virtual methods, so has to fallback to the IMT trampoline.
1394 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1396 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1399 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1403 if (imt_builder [i] != NULL) {
1404 int methods_in_slot = imt_builder [i]->children + 1;
1405 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1406 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1407 record_method_count_for_max_collisions = TRUE;
1409 method_count += methods_in_slot;
1413 mono_stats.imt_number_of_methods += method_count;
1414 if (record_method_count_for_max_collisions) {
1415 mono_stats.imt_method_count_when_max_collisions = method_count;
1418 for (i = 0; i < MONO_IMT_SIZE; i++) {
1419 MonoImtBuilderEntry* entry = imt_builder [i];
1420 while (entry != NULL) {
1421 MonoImtBuilderEntry* next = entry->next;
1427 /* we OR the bitmap since we may build just a single imt slot at a time */
1428 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1432 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1433 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1437 * mono_vtable_build_imt_slot:
1438 * @vtable: virtual object table struct
1439 * @imt_slot: slot in the IMT table
1441 * Fill the given @imt_slot in the IMT table of @vtable with
1442 * a trampoline or a thunk for the case of collisions.
1443 * This is part of the internal mono API.
1445 * LOCKING: Take the domain lock.
1448 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1450 gpointer *imt = (gpointer*)vtable;
1451 imt -= MONO_IMT_SIZE;
1452 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1454 /* no support for extra interfaces: the proxy objects will need
1455 * to build the complete IMT
1456 * Update and heck needs to ahppen inside the proper domain lock, as all
1457 * the changes made to a MonoVTable.
1459 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1460 mono_domain_lock (vtable->domain);
1461 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1462 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1463 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1464 mono_domain_unlock (vtable->domain);
1465 mono_loader_unlock ();
1470 * The first two free list entries both belong to the wait list: The
1471 * first entry is the pointer to the head of the list and the second
1472 * entry points to the last element. That way appending and removing
1473 * the first element are both O(1) operations.
1475 #ifdef MONO_SMALL_CONFIG
1476 #define NUM_FREE_LISTS 6
1478 #define NUM_FREE_LISTS 12
1480 #define FIRST_FREE_LIST_SIZE 64
1481 #define MAX_WAIT_LENGTH 50
1482 #define THUNK_THRESHOLD 10
1485 * LOCKING: The domain lock must be held.
1488 init_thunk_free_lists (MonoDomain *domain)
1490 if (domain->thunk_free_lists)
1492 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1496 list_index_for_size (int item_size)
1499 int size = FIRST_FREE_LIST_SIZE;
1501 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1510 * mono_method_alloc_generic_virtual_thunk:
1512 * @size: size in bytes
1514 * Allocs size bytes to be used for the code of a generic virtual
1515 * thunk. It's either allocated from the domain's code manager or
1516 * reused from a previously invalidated piece.
1518 * LOCKING: The domain lock must be held.
1521 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1523 static gboolean inited = FALSE;
1524 static int generic_virtual_thunks_size = 0;
1528 MonoThunkFreeList **l;
1530 init_thunk_free_lists (domain);
1532 size += sizeof (guint32);
1533 if (size < sizeof (MonoThunkFreeList))
1534 size = sizeof (MonoThunkFreeList);
1536 i = list_index_for_size (size);
1537 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1538 if ((*l)->size >= size) {
1539 MonoThunkFreeList *item = *l;
1541 return ((guint32*)item) + 1;
1545 /* no suitable item found - search lists of larger sizes */
1546 while (++i < NUM_FREE_LISTS) {
1547 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1550 g_assert (item->size > size);
1551 domain->thunk_free_lists [i] = item->next;
1552 return ((guint32*)item) + 1;
1555 /* still nothing found - allocate it */
1557 mono_counters_register ("Generic virtual thunk bytes",
1558 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1561 generic_virtual_thunks_size += size;
1563 p = mono_domain_code_reserve (domain, size);
1566 mono_domain_lock (domain);
1567 if (!domain->generic_virtual_thunks)
1568 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1569 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1570 mono_domain_unlock (domain);
1576 * LOCKING: The domain lock must be held.
1579 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1582 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1583 gboolean found = FALSE;
1585 mono_domain_lock (domain);
1586 if (!domain->generic_virtual_thunks)
1587 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1588 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1590 mono_domain_unlock (domain);
1593 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1595 init_thunk_free_lists (domain);
1597 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1598 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1599 int length = item->length;
1602 /* unlink the first item from the wait list */
1603 domain->thunk_free_lists [0] = item->next;
1604 domain->thunk_free_lists [0]->length = length - 1;
1606 i = list_index_for_size (item->size);
1608 /* put it in the free list */
1609 item->next = domain->thunk_free_lists [i];
1610 domain->thunk_free_lists [i] = item;
1614 if (domain->thunk_free_lists [1]) {
1615 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1616 domain->thunk_free_lists [0]->length++;
1618 g_assert (!domain->thunk_free_lists [0]);
1620 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1621 domain->thunk_free_lists [0]->length = 1;
1625 typedef struct _GenericVirtualCase {
1629 struct _GenericVirtualCase *next;
1630 } GenericVirtualCase;
1633 * get_generic_virtual_entries:
1635 * Return IMT entries for the generic virtual method instances and
1636 * variant interface methods for vtable slot
1639 static MonoImtBuilderEntry*
1640 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1642 GenericVirtualCase *list;
1643 MonoImtBuilderEntry *entries;
1645 mono_domain_lock (domain);
1646 if (!domain->generic_virtual_cases)
1647 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1649 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1652 for (; list; list = list->next) {
1653 MonoImtBuilderEntry *entry;
1655 if (list->count < THUNK_THRESHOLD)
1658 entry = g_new0 (MonoImtBuilderEntry, 1);
1659 entry->key = list->method;
1660 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1661 entry->has_target_code = 1;
1663 entry->children = entries->children + 1;
1664 entry->next = entries;
1668 mono_domain_unlock (domain);
1670 /* FIXME: Leaking memory ? */
1675 * mono_method_add_generic_virtual_invocation:
1677 * @vtable_slot: pointer to the vtable slot
1678 * @method: the inflated generic virtual method
1679 * @code: the method's code
1681 * Registers a call via unmanaged code to a generic virtual method
1682 * instantiation or variant interface method. If the number of calls reaches a threshold
1683 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1684 * virtual method thunk.
1687 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1688 gpointer *vtable_slot,
1689 MonoMethod *method, gpointer code)
1691 static gboolean inited = FALSE;
1692 static int num_added = 0;
1694 GenericVirtualCase *gvc, *list;
1695 MonoImtBuilderEntry *entries;
1699 mono_domain_lock (domain);
1700 if (!domain->generic_virtual_cases)
1701 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1703 /* Check whether the case was already added */
1704 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1707 if (gvc->method == method)
1712 /* If not found, make a new one */
1714 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1715 gvc->method = method;
1718 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1720 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1723 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1729 if (++gvc->count == THUNK_THRESHOLD) {
1730 gpointer *old_thunk = *vtable_slot;
1731 gpointer vtable_trampoline = NULL;
1732 gpointer imt_trampoline = NULL;
1734 if ((gpointer)vtable_slot < (gpointer)vtable) {
1735 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1736 int imt_slot = MONO_IMT_SIZE + displacement;
1738 /* Force the rebuild of the thunk at the next call */
1739 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1740 *vtable_slot = imt_trampoline;
1742 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1744 entries = get_generic_virtual_entries (domain, vtable_slot);
1746 sorted = imt_sort_slot_entries (entries);
1748 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1752 MonoImtBuilderEntry *next = entries->next;
1757 for (i = 0; i < sorted->len; ++i)
1758 g_free (g_ptr_array_index (sorted, i));
1759 g_ptr_array_free (sorted, TRUE);
1762 #ifndef __native_client__
1763 /* We don't re-use any thunks as there is a lot of overhead */
1764 /* to deleting and re-using code in Native Client. */
1765 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1766 invalidate_generic_virtual_thunk (domain, old_thunk);
1770 mono_domain_unlock (domain);
1773 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1776 * mono_class_vtable:
1777 * @domain: the application domain
1778 * @class: the class to initialize
1780 * VTables are domain specific because we create domain specific code, and
1781 * they contain the domain specific static class data.
1782 * On failure, NULL is returned, and class->exception_type is set.
1785 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1787 return mono_class_vtable_full (domain, class, FALSE);
1791 * mono_class_vtable_full:
1792 * @domain: the application domain
1793 * @class: the class to initialize
1794 * @raise_on_error if an exception should be raised on failure or not
1796 * VTables are domain specific because we create domain specific code, and
1797 * they contain the domain specific static class data.
1800 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1802 MonoClassRuntimeInfo *runtime_info;
1806 if (class->exception_type) {
1808 mono_raise_exception (mono_class_get_exception_for_failure (class));
1812 /* this check can be inlined in jitted code, too */
1813 runtime_info = class->runtime_info;
1814 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1815 return runtime_info->domain_vtables [domain->domain_id];
1816 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1820 * mono_class_try_get_vtable:
1821 * @domain: the application domain
1822 * @class: the class to initialize
1824 * This function tries to get the associated vtable from @class if
1825 * it was already created.
1828 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1830 MonoClassRuntimeInfo *runtime_info;
1834 runtime_info = class->runtime_info;
1835 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1836 return runtime_info->domain_vtables [domain->domain_id];
1841 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1844 MonoClassRuntimeInfo *runtime_info, *old_info;
1845 MonoClassField *field;
1847 int i, vtable_slots;
1848 int imt_table_bytes = 0;
1850 guint32 vtable_size, class_size;
1853 gpointer *interface_offsets;
1855 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1856 mono_domain_lock (domain);
1857 runtime_info = class->runtime_info;
1858 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1859 mono_domain_unlock (domain);
1860 mono_loader_unlock ();
1861 return runtime_info->domain_vtables [domain->domain_id];
1863 if (!class->inited || class->exception_type) {
1864 if (!mono_class_init (class) || class->exception_type) {
1865 mono_domain_unlock (domain);
1866 mono_loader_unlock ();
1868 mono_raise_exception (mono_class_get_exception_for_failure (class));
1873 /* Array types require that their element type be valid*/
1874 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1875 MonoClass *element_class = class->element_class;
1876 if (!element_class->inited)
1877 mono_class_init (element_class);
1879 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1880 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1881 mono_class_setup_vtable (element_class);
1883 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1884 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1885 if (class->exception_type == MONO_EXCEPTION_NONE)
1886 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1887 mono_domain_unlock (domain);
1888 mono_loader_unlock ();
1890 mono_raise_exception (mono_class_get_exception_for_failure (class));
1896 * For some classes, mono_class_init () already computed class->vtable_size, and
1897 * that is all that is needed because of the vtable trampolines.
1899 if (!class->vtable_size)
1900 mono_class_setup_vtable (class);
1902 if (class->generic_class && !class->vtable)
1903 mono_class_check_vtable_constraints (class, NULL);
1905 /* Initialize klass->has_finalize */
1906 mono_class_has_finalizer (class);
1908 if (class->exception_type) {
1909 mono_domain_unlock (domain);
1910 mono_loader_unlock ();
1912 mono_raise_exception (mono_class_get_exception_for_failure (class));
1916 vtable_slots = class->vtable_size;
1917 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1918 class_size = mono_class_data_size (class);
1923 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1924 if (class->interface_offsets_count) {
1925 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1926 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1927 mono_stats.imt_number_of_tables++;
1928 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1931 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1932 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1935 mono_stats.used_class_count++;
1936 mono_stats.class_vtable_size += vtable_size;
1937 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1940 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1942 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1944 vt->rank = class->rank;
1945 vt->domain = domain;
1947 mono_class_compute_gc_descriptor (class);
1949 * We can't use typed allocation in the non-root domains, since the
1950 * collector needs the GC descriptor stored in the vtable even after
1951 * the mempool containing the vtable is destroyed when the domain is
1952 * unloaded. An alternative might be to allocate vtables in the GC
1953 * heap, but this does not seem to work (it leads to crashes inside
1954 * libgc). If that approach is tried, two gc descriptors need to be
1955 * allocated for each class: one for the root domain, and one for all
1956 * other domains. The second descriptor should contain a bit for the
1957 * vtable field in MonoObject, since we can no longer assume the
1958 * vtable is reachable by other roots after the appdomain is unloaded.
1960 #ifdef HAVE_BOEHM_GC
1961 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1962 vt->gc_descr = GC_NO_DESCRIPTOR;
1965 vt->gc_descr = class->gc_descr;
1967 gc_bits = mono_gc_get_vtable_bits (class);
1968 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1970 vt->gc_bits = gc_bits;
1973 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1974 if (class->has_static_refs) {
1975 gpointer statics_gc_descr;
1977 gsize default_bitmap [4] = {0};
1980 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1981 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1982 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1983 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1984 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1985 if (bitmap != default_bitmap)
1988 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1990 vt->has_static_fields = TRUE;
1991 mono_stats.class_static_data_size += class_size;
1996 while ((field = mono_class_get_fields (class, &iter))) {
1997 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1999 if (mono_field_is_deleted (field))
2001 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2002 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2003 if (special_static != SPECIAL_STATIC_NONE) {
2004 guint32 size, offset;
2006 gsize default_bitmap [4] = {0};
2011 if (mono_type_is_reference (field->type)) {
2012 default_bitmap [0] = 1;
2014 bitmap = default_bitmap;
2015 } else if (mono_type_is_struct (field->type)) {
2016 fclass = mono_class_from_mono_type (field->type);
2017 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2018 numbits = max_set + 1;
2020 default_bitmap [0] = 0;
2022 bitmap = default_bitmap;
2024 size = mono_type_size (field->type, &align);
2025 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2026 if (!domain->special_static_fields)
2027 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2028 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2029 if (bitmap != default_bitmap)
2032 * This marks the field as special static to speed up the
2033 * checks in mono_field_static_get/set_value ().
2039 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2040 MonoClass *fklass = mono_class_from_mono_type (field->type);
2041 const char *data = mono_field_get_data (field);
2043 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2044 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2045 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2048 if (fklass->valuetype) {
2049 memcpy (t, data, mono_class_value_size (fklass, NULL));
2051 /* it's a pointer type: add check */
2052 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2059 vt->max_interface_id = class->max_interface_id;
2060 vt->interface_bitmap = class->interface_bitmap;
2062 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2063 // class->name, class->interface_offsets_count);
2065 if (! ARCH_USE_IMT) {
2066 /* initialize interface offsets */
2067 for (i = 0; i < class->interface_offsets_count; ++i) {
2068 int interface_id = class->interfaces_packed [i]->interface_id;
2069 int slot = class->interface_offsets_packed [i];
2070 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2074 /* Initialize vtable */
2075 if (callbacks.get_vtable_trampoline) {
2076 // This also covers the AOT case
2077 for (i = 0; i < class->vtable_size; ++i) {
2078 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2081 mono_class_setup_vtable (class);
2083 for (i = 0; i < class->vtable_size; ++i) {
2086 if ((cm = class->vtable [i]))
2087 vt->vtable [i] = arch_create_jit_trampoline (cm);
2091 if (ARCH_USE_IMT && imt_table_bytes) {
2092 /* Now that the vtable is full, we can actually fill up the IMT */
2093 if (callbacks.get_imt_trampoline) {
2094 /* lazy construction of the IMT entries enabled */
2095 for (i = 0; i < MONO_IMT_SIZE; ++i)
2096 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2098 build_imt (class, vt, domain, interface_offsets, NULL);
2103 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2104 * re-acquire them and check if another thread has created the vtable in the meantime.
2106 /* Special case System.MonoType to avoid infinite recursion */
2107 if (class != mono_defaults.monotype_class) {
2108 /*FIXME check for OOM*/
2109 vt->type = mono_type_get_object (domain, &class->byval_arg);
2110 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2111 /* This is unregistered in
2112 unregister_vtable_reflection_type() in
2114 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2117 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2119 /* class_vtable_array keeps an array of created vtables
2121 g_ptr_array_add (domain->class_vtable_array, vt);
2122 /* class->runtime_info is protected by the loader lock, both when
2123 * it it enlarged and when it is stored info.
2127 * Store the vtable in class->runtime_info.
2128 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2130 mono_memory_barrier ();
2132 old_info = class->runtime_info;
2133 if (old_info && old_info->max_domain >= domain->domain_id) {
2134 /* someone already created a large enough runtime info */
2135 old_info->domain_vtables [domain->domain_id] = vt;
2137 int new_size = domain->domain_id;
2139 new_size = MAX (new_size, old_info->max_domain);
2141 /* make the new size a power of two */
2143 while (new_size > i)
2146 /* this is a bounded memory retention issue: may want to
2147 * handle it differently when we'll have a rcu-like system.
2149 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2150 runtime_info->max_domain = new_size - 1;
2151 /* copy the stuff from the older info */
2153 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2155 runtime_info->domain_vtables [domain->domain_id] = vt;
2157 mono_memory_barrier ();
2158 class->runtime_info = runtime_info;
2161 if (class == mono_defaults.monotype_class) {
2162 /*FIXME check for OOM*/
2163 vt->type = mono_type_get_object (domain, &class->byval_arg);
2164 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2165 /* This is unregistered in
2166 unregister_vtable_reflection_type() in
2168 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2171 mono_domain_unlock (domain);
2172 mono_loader_unlock ();
2174 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2175 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2176 mono_raise_exception (mono_class_get_exception_for_failure (class));
2178 /* make sure the parent is initialized */
2179 /*FIXME shouldn't this fail the current type?*/
2181 mono_class_vtable_full (domain, class->parent, raise_on_error);
2186 #ifndef DISABLE_REMOTING
2188 * mono_class_proxy_vtable:
2189 * @domain: the application domain
2190 * @remove_class: the remote class
2192 * Creates a vtable for transparent proxies. It is basically
2193 * a copy of the real vtable of the class wrapped in @remote_class,
2194 * but all function pointers invoke the remoting functions, and
2195 * vtable->klass points to the transparent proxy class, and not to @class.
2198 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2201 MonoVTable *vt, *pvt;
2202 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2204 GSList *extra_interfaces = NULL;
2205 MonoClass *class = remote_class->proxy_class;
2206 gpointer *interface_offsets;
2210 #ifdef COMPRESSED_INTERFACE_BITMAP
2214 vt = mono_class_vtable (domain, class);
2215 g_assert (vt); /*FIXME property handle failure*/
2216 max_interface_id = vt->max_interface_id;
2218 /* Calculate vtable space for extra interfaces */
2219 for (j = 0; j < remote_class->interface_count; j++) {
2220 MonoClass* iclass = remote_class->interfaces[j];
2224 /*FIXME test for interfaces with variant generic arguments*/
2225 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2226 continue; /* interface implemented by the class */
2227 if (g_slist_find (extra_interfaces, iclass))
2230 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2232 method_count = mono_class_num_methods (iclass);
2234 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2235 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2237 for (i = 0; i < ifaces->len; ++i) {
2238 MonoClass *ic = g_ptr_array_index (ifaces, i);
2239 /*FIXME test for interfaces with variant generic arguments*/
2240 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2241 continue; /* interface implemented by the class */
2242 if (g_slist_find (extra_interfaces, ic))
2244 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2245 method_count += mono_class_num_methods (ic);
2247 g_ptr_array_free (ifaces, TRUE);
2250 extra_interface_vtsize += method_count * sizeof (gpointer);
2251 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2255 mono_stats.imt_number_of_tables++;
2256 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2257 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2258 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2260 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2261 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2264 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2266 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2268 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2270 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2271 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2273 pvt->klass = mono_defaults.transparent_proxy_class;
2274 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2275 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2277 /* initialize vtable */
2278 mono_class_setup_vtable (class);
2279 for (i = 0; i < class->vtable_size; ++i) {
2282 if ((cm = class->vtable [i]))
2283 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2285 pvt->vtable [i] = NULL;
2288 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2289 /* create trampolines for abstract methods */
2290 for (k = class; k; k = k->parent) {
2292 gpointer iter = NULL;
2293 while ((m = mono_class_get_methods (k, &iter)))
2294 if (!pvt->vtable [m->slot])
2295 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2299 pvt->max_interface_id = max_interface_id;
2300 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2301 #ifdef COMPRESSED_INTERFACE_BITMAP
2302 bitmap = g_malloc0 (bsize);
2304 bitmap = mono_domain_alloc0 (domain, bsize);
2307 if (! ARCH_USE_IMT) {
2308 /* initialize interface offsets */
2309 for (i = 0; i < class->interface_offsets_count; ++i) {
2310 int interface_id = class->interfaces_packed [i]->interface_id;
2311 int slot = class->interface_offsets_packed [i];
2312 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2315 for (i = 0; i < class->interface_offsets_count; ++i) {
2316 int interface_id = class->interfaces_packed [i]->interface_id;
2317 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2320 if (extra_interfaces) {
2321 int slot = class->vtable_size;
2327 /* Create trampolines for the methods of the interfaces */
2328 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2329 interf = list_item->data;
2331 if (! ARCH_USE_IMT) {
2332 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2334 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2338 while ((cm = mono_class_get_methods (interf, &iter)))
2339 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2341 slot += mono_class_num_methods (interf);
2343 if (! ARCH_USE_IMT) {
2344 g_slist_free (extra_interfaces);
2349 /* Now that the vtable is full, we can actually fill up the IMT */
2350 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2351 if (extra_interfaces) {
2352 g_slist_free (extra_interfaces);
2356 #ifdef COMPRESSED_INTERFACE_BITMAP
2357 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2358 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2359 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2362 pvt->interface_bitmap = bitmap;
2367 #endif /* DISABLE_REMOTING */
2370 * mono_class_field_is_special_static:
2372 * Returns whether @field is a thread/context static field.
2375 mono_class_field_is_special_static (MonoClassField *field)
2377 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2379 if (mono_field_is_deleted (field))
2381 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2382 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2389 * mono_class_field_get_special_static_type:
2390 * @field: The MonoClassField describing the field.
2392 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2393 * SPECIAL_STATIC_NONE otherwise.
2396 mono_class_field_get_special_static_type (MonoClassField *field)
2398 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2399 return SPECIAL_STATIC_NONE;
2400 if (mono_field_is_deleted (field))
2401 return SPECIAL_STATIC_NONE;
2402 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2403 return field_is_special_static (field->parent, field);
2404 return SPECIAL_STATIC_NONE;
2408 * mono_class_has_special_static_fields:
2410 * Returns whenever @klass has any thread/context static fields.
2413 mono_class_has_special_static_fields (MonoClass *klass)
2415 MonoClassField *field;
2419 while ((field = mono_class_get_fields (klass, &iter))) {
2420 g_assert (field->parent == klass);
2421 if (mono_class_field_is_special_static (field))
2428 #ifndef DISABLE_REMOTING
2430 * create_remote_class_key:
2431 * Creates an array of pointers that can be used as a hash key for a remote class.
2432 * The first element of the array is the number of pointers.
2435 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2440 if (remote_class == NULL) {
2441 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2442 key = g_malloc (sizeof(gpointer) * 3);
2443 key [0] = GINT_TO_POINTER (2);
2444 key [1] = mono_defaults.marshalbyrefobject_class;
2445 key [2] = extra_class;
2447 key = g_malloc (sizeof(gpointer) * 2);
2448 key [0] = GINT_TO_POINTER (1);
2449 key [1] = extra_class;
2452 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2453 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2454 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2455 key [1] = remote_class->proxy_class;
2457 // Keep the list of interfaces sorted
2458 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2459 if (extra_class && remote_class->interfaces [i] > extra_class) {
2460 key [j++] = extra_class;
2463 key [j] = remote_class->interfaces [i];
2466 key [j] = extra_class;
2468 // Replace the old class. The interface list is the same
2469 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2470 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2471 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2472 for (i = 0; i < remote_class->interface_count; i++)
2473 key [2 + i] = remote_class->interfaces [i];
2481 * copy_remote_class_key:
2483 * Make a copy of KEY in the domain and return the copy.
2486 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2488 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2489 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2491 memcpy (mp_key, key, key_size);
2497 * mono_remote_class:
2498 * @domain: the application domain
2499 * @class_name: name of the remote class
2501 * Creates and initializes a MonoRemoteClass object for a remote type.
2503 * Can raise an exception on failure.
2506 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2509 MonoRemoteClass *rc;
2510 gpointer* key, *mp_key;
2513 key = create_remote_class_key (NULL, proxy_class);
2515 mono_domain_lock (domain);
2516 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2520 mono_domain_unlock (domain);
2524 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2525 if (!mono_error_ok (&error)) {
2527 mono_domain_unlock (domain);
2528 mono_error_raise_exception (&error);
2531 mp_key = copy_remote_class_key (domain, key);
2535 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2536 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2537 rc->interface_count = 1;
2538 rc->interfaces [0] = proxy_class;
2539 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2541 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2542 rc->interface_count = 0;
2543 rc->proxy_class = proxy_class;
2546 rc->default_vtable = NULL;
2547 rc->xdomain_vtable = NULL;
2548 rc->proxy_class_name = name;
2549 #ifndef DISABLE_PERFCOUNTERS
2550 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2553 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2555 mono_domain_unlock (domain);
2560 * clone_remote_class:
2561 * Creates a copy of the remote_class, adding the provided class or interface
2563 static MonoRemoteClass*
2564 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2566 MonoRemoteClass *rc;
2567 gpointer* key, *mp_key;
2569 key = create_remote_class_key (remote_class, extra_class);
2570 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2576 mp_key = copy_remote_class_key (domain, key);
2580 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2582 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2583 rc->proxy_class = remote_class->proxy_class;
2584 rc->interface_count = remote_class->interface_count + 1;
2586 // Keep the list of interfaces sorted, since the hash key of
2587 // the remote class depends on this
2588 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2589 if (remote_class->interfaces [i] > extra_class && i == j)
2590 rc->interfaces [j++] = extra_class;
2591 rc->interfaces [j] = remote_class->interfaces [i];
2594 rc->interfaces [j] = extra_class;
2596 // Replace the old class. The interface array is the same
2597 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2598 rc->proxy_class = extra_class;
2599 rc->interface_count = remote_class->interface_count;
2600 if (rc->interface_count > 0)
2601 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2604 rc->default_vtable = NULL;
2605 rc->xdomain_vtable = NULL;
2606 rc->proxy_class_name = remote_class->proxy_class_name;
2608 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2614 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2616 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2617 mono_domain_lock (domain);
2618 if (rp->target_domain_id != -1) {
2619 if (remote_class->xdomain_vtable == NULL)
2620 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2621 mono_domain_unlock (domain);
2622 mono_loader_unlock ();
2623 return remote_class->xdomain_vtable;
2625 if (remote_class->default_vtable == NULL) {
2628 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2629 klass = mono_class_from_mono_type (type);
2631 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)))
2632 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2635 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2638 mono_domain_unlock (domain);
2639 mono_loader_unlock ();
2640 return remote_class->default_vtable;
2644 * mono_upgrade_remote_class:
2645 * @domain: the application domain
2646 * @tproxy: the proxy whose remote class has to be upgraded.
2647 * @klass: class to which the remote class can be casted.
2649 * Updates the vtable of the remote class by adding the necessary method slots
2650 * and interface offsets so it can be safely casted to klass. klass can be a
2651 * class or an interface.
2654 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2656 MonoTransparentProxy *tproxy;
2657 MonoRemoteClass *remote_class;
2658 gboolean redo_vtable;
2660 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2661 mono_domain_lock (domain);
2663 tproxy = (MonoTransparentProxy*) proxy_object;
2664 remote_class = tproxy->remote_class;
2666 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2669 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2670 if (remote_class->interfaces [i] == klass)
2671 redo_vtable = FALSE;
2674 redo_vtable = (remote_class->proxy_class != klass);
2678 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2679 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2682 mono_domain_unlock (domain);
2683 mono_loader_unlock ();
2685 #endif /* DISABLE_REMOTING */
2689 * mono_object_get_virtual_method:
2690 * @obj: object to operate on.
2693 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2694 * the instance of a callvirt of method.
2697 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2700 MonoMethod **vtable;
2701 gboolean is_proxy = FALSE;
2702 MonoMethod *res = NULL;
2704 klass = mono_object_class (obj);
2705 #ifndef DISABLE_REMOTING
2706 if (klass == mono_defaults.transparent_proxy_class) {
2707 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2712 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2715 mono_class_setup_vtable (klass);
2716 vtable = klass->vtable;
2718 if (method->slot == -1) {
2719 /* method->slot might not be set for instances of generic methods */
2720 if (method->is_inflated) {
2721 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2722 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2725 g_assert_not_reached ();
2729 /* check method->slot is a valid index: perform isinstance? */
2730 if (method->slot != -1) {
2731 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2733 gboolean variance_used = FALSE;
2734 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2735 g_assert (iface_offset > 0);
2736 res = vtable [iface_offset + method->slot];
2739 res = vtable [method->slot];
2743 #ifndef DISABLE_REMOTING
2745 /* It may be an interface, abstract class method or generic method */
2746 if (!res || mono_method_signature (res)->generic_param_count)
2749 /* generic methods demand invoke_with_check */
2750 if (mono_method_signature (res)->generic_param_count)
2751 res = mono_marshal_get_remoting_invoke_with_check (res);
2754 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2755 res = mono_cominterop_get_invoke (res);
2758 res = mono_marshal_get_remoting_invoke (res);
2763 if (method->is_inflated) {
2764 /* Have to inflate the result */
2765 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2775 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2777 g_error ("runtime invoke called on uninitialized runtime");
2781 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2784 * mono_runtime_invoke:
2785 * @method: method to invoke
2786 * @obJ: object instance
2787 * @params: arguments to the method
2788 * @exc: exception information.
2790 * Invokes the method represented by @method on the object @obj.
2792 * obj is the 'this' pointer, it should be NULL for static
2793 * methods, a MonoObject* for object instances and a pointer to
2794 * the value type for value types.
2796 * The params array contains the arguments to the method with the
2797 * same convention: MonoObject* pointers for object instances and
2798 * pointers to the value type otherwise.
2800 * From unmanaged code you'll usually use the
2801 * mono_runtime_invoke() variant.
2803 * Note that this function doesn't handle virtual methods for
2804 * you, it will exec the exact method you pass: we still need to
2805 * expose a function to lookup the derived class implementation
2806 * of a virtual method (there are examples of this in the code,
2809 * You can pass NULL as the exc argument if you don't want to
2810 * catch exceptions, otherwise, *exc will be set to the exception
2811 * thrown, if any. if an exception is thrown, you can't use the
2812 * MonoObject* result from the function.
2814 * If the method returns a value type, it is boxed in an object
2818 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2822 if (mono_runtime_get_no_exec ())
2823 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2825 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2826 mono_profiler_method_start_invoke (method);
2828 result = default_mono_runtime_invoke (method, obj, params, exc);
2830 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2831 mono_profiler_method_end_invoke (method);
2837 * mono_method_get_unmanaged_thunk:
2838 * @method: method to generate a thunk for.
2840 * Returns an unmanaged->managed thunk that can be used to call
2841 * a managed method directly from C.
2843 * The thunk's C signature closely matches the managed signature:
2845 * C#: public bool Equals (object obj);
2846 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2847 * MonoObject*, MonoException**);
2849 * The 1st ("this") parameter must not be used with static methods:
2851 * C#: public static bool ReferenceEquals (object a, object b);
2852 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2855 * The last argument must be a non-null pointer of a MonoException* pointer.
2856 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2857 * exception has been thrown in managed code. Otherwise it will point
2858 * to the MonoException* caught by the thunk. In this case, the result of
2859 * the thunk is undefined:
2861 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2862 * MonoException *ex = NULL;
2863 * Equals func = mono_method_get_unmanaged_thunk (method);
2864 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2866 * // handle exception
2869 * The calling convention of the thunk matches the platform's default
2870 * convention. This means that under Windows, C declarations must
2871 * contain the __stdcall attribute:
2873 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2874 * MonoObject*, MonoException**);
2878 * Value type arguments and return values are treated as they were objects:
2880 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2881 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2883 * Arguments must be properly boxed upon trunk's invocation, while return
2884 * values must be unboxed.
2887 mono_method_get_unmanaged_thunk (MonoMethod *method)
2889 method = mono_marshal_get_thunk_invoke_wrapper (method);
2890 return mono_compile_method (method);
2894 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2898 /* object fields cannot be byref, so we don't need a
2900 gpointer *p = (gpointer*)dest;
2907 case MONO_TYPE_BOOLEAN:
2909 case MONO_TYPE_U1: {
2910 guint8 *p = (guint8*)dest;
2911 *p = value ? *(guint8*)value : 0;
2916 case MONO_TYPE_CHAR: {
2917 guint16 *p = (guint16*)dest;
2918 *p = value ? *(guint16*)value : 0;
2921 #if SIZEOF_VOID_P == 4
2926 case MONO_TYPE_U4: {
2927 gint32 *p = (gint32*)dest;
2928 *p = value ? *(gint32*)value : 0;
2931 #if SIZEOF_VOID_P == 8
2936 case MONO_TYPE_U8: {
2937 gint64 *p = (gint64*)dest;
2938 *p = value ? *(gint64*)value : 0;
2941 case MONO_TYPE_R4: {
2942 float *p = (float*)dest;
2943 *p = value ? *(float*)value : 0;
2946 case MONO_TYPE_R8: {
2947 double *p = (double*)dest;
2948 *p = value ? *(double*)value : 0;
2951 case MONO_TYPE_STRING:
2952 case MONO_TYPE_SZARRAY:
2953 case MONO_TYPE_CLASS:
2954 case MONO_TYPE_OBJECT:
2955 case MONO_TYPE_ARRAY:
2956 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2958 case MONO_TYPE_FNPTR:
2959 case MONO_TYPE_PTR: {
2960 gpointer *p = (gpointer*)dest;
2961 *p = deref_pointer? *(gpointer*)value: value;
2964 case MONO_TYPE_VALUETYPE:
2965 /* note that 't' and 'type->type' can be different */
2966 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2967 t = mono_class_enum_basetype (type->data.klass)->type;
2970 MonoClass *class = mono_class_from_mono_type (type);
2971 int size = mono_class_value_size (class, NULL);
2973 mono_gc_bzero_atomic (dest, size);
2975 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2978 case MONO_TYPE_GENERICINST:
2979 t = type->data.generic_class->container_class->byval_arg.type;
2982 g_error ("got type %x", type->type);
2987 * mono_field_set_value:
2988 * @obj: Instance object
2989 * @field: MonoClassField describing the field to set
2990 * @value: The value to be set
2992 * Sets the value of the field described by @field in the object instance @obj
2993 * to the value passed in @value. This method should only be used for instance
2994 * fields. For static fields, use mono_field_static_set_value.
2996 * The value must be on the native format of the field type.
2999 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3003 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3005 dest = (char*)obj + field->offset;
3006 set_value (field->type, dest, value, FALSE);
3010 * mono_field_static_set_value:
3011 * @field: MonoClassField describing the field to set
3012 * @value: The value to be set
3014 * Sets the value of the static field described by @field
3015 * to the value passed in @value.
3017 * The value must be on the native format of the field type.
3020 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3024 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3025 /* you cant set a constant! */
3026 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3028 if (field->offset == -1) {
3029 /* Special static */
3032 mono_domain_lock (vt->domain);
3033 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3034 mono_domain_unlock (vt->domain);
3035 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3037 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3039 set_value (field->type, dest, value, FALSE);
3043 * mono_vtable_get_static_field_data:
3045 * Internal use function: return a pointer to the memory holding the static fields
3046 * for a class or NULL if there are no static fields.
3047 * This is exported only for use by the debugger.
3050 mono_vtable_get_static_field_data (MonoVTable *vt)
3052 if (!vt->has_static_fields)
3054 return vt->vtable [vt->klass->vtable_size];
3058 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3062 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3063 if (field->offset == -1) {
3064 /* Special static */
3067 mono_domain_lock (vt->domain);
3068 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3069 mono_domain_unlock (vt->domain);
3070 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3072 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3075 src = (guint8*)obj + field->offset;
3082 * mono_field_get_value:
3083 * @obj: Object instance
3084 * @field: MonoClassField describing the field to fetch information from
3085 * @value: pointer to the location where the value will be stored
3087 * Use this routine to get the value of the field @field in the object
3090 * The pointer provided by value must be of the field type, for reference
3091 * types this is a MonoObject*, for value types its the actual pointer to
3096 * mono_field_get_value (obj, int_field, &i);
3099 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3105 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3107 src = (char*)obj + field->offset;
3108 set_value (field->type, value, src, TRUE);
3112 * mono_field_get_value_object:
3113 * @domain: domain where the object will be created (if boxing)
3114 * @field: MonoClassField describing the field to fetch information from
3115 * @obj: The object instance for the field.
3117 * Returns: a new MonoObject with the value from the given field. If the
3118 * field represents a value type, the value is boxed.
3122 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3126 MonoVTable *vtable = NULL;
3128 gboolean is_static = FALSE;
3129 gboolean is_ref = FALSE;
3130 gboolean is_literal = FALSE;
3131 gboolean is_ptr = FALSE;
3133 MonoType *type = mono_field_get_type_checked (field, &error);
3135 if (!mono_error_ok (&error))
3136 mono_error_raise_exception (&error);
3138 switch (type->type) {
3139 case MONO_TYPE_STRING:
3140 case MONO_TYPE_OBJECT:
3141 case MONO_TYPE_CLASS:
3142 case MONO_TYPE_ARRAY:
3143 case MONO_TYPE_SZARRAY:
3148 case MONO_TYPE_BOOLEAN:
3151 case MONO_TYPE_CHAR:
3160 case MONO_TYPE_VALUETYPE:
3161 is_ref = type->byref;
3163 case MONO_TYPE_GENERICINST:
3164 is_ref = !mono_type_generic_inst_is_valuetype (type);
3170 g_error ("type 0x%x not handled in "
3171 "mono_field_get_value_object", type->type);
3175 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3178 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3182 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3183 if (!vtable->initialized)
3184 mono_runtime_class_init (vtable);
3192 get_default_field_value (domain, field, &o);
3193 } else if (is_static) {
3194 mono_field_static_get_value (vtable, field, &o);
3196 mono_field_get_value (obj, field, &o);
3202 static MonoMethod *m;
3208 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3209 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3215 get_default_field_value (domain, field, v);
3216 } else if (is_static) {
3217 mono_field_static_get_value (vtable, field, v);
3219 mono_field_get_value (obj, field, v);
3222 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3224 args [1] = mono_type_get_object (mono_domain_get (), type);
3226 return mono_runtime_invoke (m, NULL, args, NULL);
3229 /* boxed value type */
3230 klass = mono_class_from_mono_type (type);
3232 if (mono_class_is_nullable (klass))
3233 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3235 o = mono_object_new (domain, klass);
3236 v = ((gchar *) o) + sizeof (MonoObject);
3239 get_default_field_value (domain, field, v);
3240 } else if (is_static) {
3241 mono_field_static_get_value (vtable, field, v);
3243 mono_field_get_value (obj, field, v);
3250 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3253 const char *p = blob;
3254 mono_metadata_decode_blob_size (p, &p);
3257 case MONO_TYPE_BOOLEAN:
3260 *(guint8 *) value = *p;
3262 case MONO_TYPE_CHAR:
3265 *(guint16*) value = read16 (p);
3269 *(guint32*) value = read32 (p);
3273 *(guint64*) value = read64 (p);
3276 readr4 (p, (float*) value);
3279 readr8 (p, (double*) value);
3281 case MONO_TYPE_STRING:
3282 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3284 case MONO_TYPE_CLASS:
3285 *(gpointer*) value = NULL;
3289 g_warning ("type 0x%02x should not be in constant table", type);
3295 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3297 MonoTypeEnum def_type;
3300 data = mono_class_get_field_default_value (field, &def_type);
3301 mono_get_constant_value_from_blob (domain, def_type, data, value);
3305 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3309 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3311 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3312 get_default_field_value (vt->domain, field, value);
3316 if (field->offset == -1) {
3317 /* Special static */
3318 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3319 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3321 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3323 set_value (field->type, value, src, TRUE);
3327 * mono_field_static_get_value:
3328 * @vt: vtable to the object
3329 * @field: MonoClassField describing the field to fetch information from
3330 * @value: where the value is returned
3332 * Use this routine to get the value of the static field @field value.
3334 * The pointer provided by value must be of the field type, for reference
3335 * types this is a MonoObject*, for value types its the actual pointer to
3340 * mono_field_static_get_value (vt, int_field, &i);
3343 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3345 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3349 * mono_property_set_value:
3350 * @prop: MonoProperty to set
3351 * @obj: instance object on which to act
3352 * @params: parameters to pass to the propery
3353 * @exc: optional exception
3355 * Invokes the property's set method with the given arguments on the
3356 * object instance obj (or NULL for static properties).
3358 * You can pass NULL as the exc argument if you don't want to
3359 * catch exceptions, otherwise, *exc will be set to the exception
3360 * thrown, if any. if an exception is thrown, you can't use the
3361 * MonoObject* result from the function.
3364 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3366 default_mono_runtime_invoke (prop->set, obj, params, exc);
3370 * mono_property_get_value:
3371 * @prop: MonoProperty to fetch
3372 * @obj: instance object on which to act
3373 * @params: parameters to pass to the propery
3374 * @exc: optional exception
3376 * Invokes the property's get method with the given arguments on the
3377 * object instance obj (or NULL for static properties).
3379 * You can pass NULL as the exc argument if you don't want to
3380 * catch exceptions, otherwise, *exc will be set to the exception
3381 * thrown, if any. if an exception is thrown, you can't use the
3382 * MonoObject* result from the function.
3384 * Returns: the value from invoking the get method on the property.
3387 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3389 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3393 * mono_nullable_init:
3394 * @buf: The nullable structure to initialize.
3395 * @value: the value to initialize from
3396 * @klass: the type for the object
3398 * Initialize the nullable structure pointed to by @buf from @value which
3399 * should be a boxed value type. The size of @buf should be able to hold
3400 * as much data as the @klass->instance_size (which is the number of bytes
3401 * that will be copies).
3403 * Since Nullables have variable structure, we can not define a C
3404 * structure for them.
3407 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3409 MonoClass *param_class = klass->cast_class;
3411 mono_class_setup_fields_locking (klass);
3412 g_assert (klass->fields_inited);
3414 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3415 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3417 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3419 if (param_class->has_references)
3420 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3422 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3424 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3429 * mono_nullable_box:
3430 * @buf: The buffer representing the data to be boxed
3431 * @klass: the type to box it as.
3433 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3437 mono_nullable_box (guint8 *buf, MonoClass *klass)
3439 MonoClass *param_class = klass->cast_class;
3441 mono_class_setup_fields_locking (klass);
3442 g_assert (klass->fields_inited);
3444 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3445 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3447 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3448 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3449 if (param_class->has_references)
3450 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3452 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3460 * mono_get_delegate_invoke:
3461 * @klass: The delegate class
3463 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3466 mono_get_delegate_invoke (MonoClass *klass)
3470 /* This is called at runtime, so avoid the slower search in metadata */
3471 mono_class_setup_methods (klass);
3472 if (klass->exception_type)
3474 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3479 * mono_get_delegate_begin_invoke:
3480 * @klass: The delegate class
3482 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3485 mono_get_delegate_begin_invoke (MonoClass *klass)
3489 /* This is called at runtime, so avoid the slower search in metadata */
3490 mono_class_setup_methods (klass);
3491 if (klass->exception_type)
3493 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3498 * mono_get_delegate_end_invoke:
3499 * @klass: The delegate class
3501 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3504 mono_get_delegate_end_invoke (MonoClass *klass)
3508 /* This is called at runtime, so avoid the slower search in metadata */
3509 mono_class_setup_methods (klass);
3510 if (klass->exception_type)
3512 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3517 * mono_runtime_delegate_invoke:
3518 * @delegate: pointer to a delegate object.
3519 * @params: parameters for the delegate.
3520 * @exc: Pointer to the exception result.
3522 * Invokes the delegate method @delegate with the parameters provided.
3524 * You can pass NULL as the exc argument if you don't want to
3525 * catch exceptions, otherwise, *exc will be set to the exception
3526 * thrown, if any. if an exception is thrown, you can't use the
3527 * MonoObject* result from the function.
3530 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3533 MonoClass *klass = delegate->vtable->klass;
3535 im = mono_get_delegate_invoke (klass);
3537 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3539 return mono_runtime_invoke (im, delegate, params, exc);
3542 static char **main_args = NULL;
3543 static int num_main_args = 0;
3546 * mono_runtime_get_main_args:
3548 * Returns: a MonoArray with the arguments passed to the main program
3551 mono_runtime_get_main_args (void)
3555 MonoDomain *domain = mono_domain_get ();
3557 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3559 for (i = 0; i < num_main_args; ++i)
3560 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3566 free_main_args (void)
3570 for (i = 0; i < num_main_args; ++i)
3571 g_free (main_args [i]);
3578 * mono_runtime_set_main_args:
3579 * @argc: number of arguments from the command line
3580 * @argv: array of strings from the command line
3582 * Set the command line arguments from an embedding application that doesn't otherwise call
3583 * mono_runtime_run_main ().
3586 mono_runtime_set_main_args (int argc, char* argv[])
3591 main_args = g_new0 (char*, argc);
3592 num_main_args = argc;
3594 for (i = 0; i < argc; ++i) {
3597 utf8_arg = mono_utf8_from_external (argv[i]);
3598 if (utf8_arg == NULL) {
3599 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3600 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3604 main_args [i] = utf8_arg;
3610 * mono_runtime_run_main:
3611 * @method: the method to start the application with (usually Main)
3612 * @argc: number of arguments from the command line
3613 * @argv: array of strings from the command line
3614 * @exc: excetption results
3616 * Execute a standard Main() method (argc/argv contains the
3617 * executable name). This method also sets the command line argument value
3618 * needed by System.Environment.
3623 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3627 MonoArray *args = NULL;
3628 MonoDomain *domain = mono_domain_get ();
3629 gchar *utf8_fullpath;
3630 MonoMethodSignature *sig;
3632 g_assert (method != NULL);
3634 mono_thread_set_main (mono_thread_current ());
3636 main_args = g_new0 (char*, argc);
3637 num_main_args = argc;
3639 if (!g_path_is_absolute (argv [0])) {
3640 gchar *basename = g_path_get_basename (argv [0]);
3641 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3645 utf8_fullpath = mono_utf8_from_external (fullpath);
3646 if(utf8_fullpath == NULL) {
3647 /* Printing the arg text will cause glib to
3648 * whinge about "Invalid UTF-8", but at least
3649 * its relevant, and shows the problem text
3652 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3653 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3660 utf8_fullpath = mono_utf8_from_external (argv[0]);
3661 if(utf8_fullpath == NULL) {
3662 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3663 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3668 main_args [0] = utf8_fullpath;
3670 for (i = 1; i < argc; ++i) {
3673 utf8_arg=mono_utf8_from_external (argv[i]);
3674 if(utf8_arg==NULL) {
3675 /* Ditto the comment about Invalid UTF-8 here */
3676 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3677 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3681 main_args [i] = utf8_arg;
3686 sig = mono_method_signature (method);
3688 g_print ("Unable to load Main method.\n");
3692 if (sig->param_count) {
3693 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3694 for (i = 0; i < argc; ++i) {
3695 /* The encodings should all work, given that
3696 * we've checked all these args for the
3699 gchar *str = mono_utf8_from_external (argv [i]);
3700 MonoString *arg = mono_string_new (domain, str);
3701 mono_array_setref (args, i, arg);
3705 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3708 mono_assembly_set_main (method->klass->image->assembly);
3710 return mono_runtime_exec_main (method, args, exc);
3714 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3716 static MonoMethod *serialize_method;
3721 if (!serialize_method) {
3722 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3723 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3726 if (!serialize_method) {
3731 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3735 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3743 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3745 static MonoMethod *deserialize_method;
3750 if (!deserialize_method) {
3751 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3752 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3754 if (!deserialize_method) {
3761 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3768 #ifndef DISABLE_REMOTING
3770 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3772 static MonoMethod *get_proxy_method;
3774 MonoDomain *domain = mono_domain_get ();
3775 MonoRealProxy *real_proxy;
3776 MonoReflectionType *reflection_type;
3777 MonoTransparentProxy *transparent_proxy;
3779 if (!get_proxy_method)
3780 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3782 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3784 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3785 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3787 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3788 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3791 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3795 return (MonoObject*) transparent_proxy;
3797 #endif /* DISABLE_REMOTING */
3800 * mono_object_xdomain_representation
3802 * @target_domain: a domain
3803 * @exc: pointer to a MonoObject*
3805 * Creates a representation of obj in the domain target_domain. This
3806 * is either a copy of obj arrived through via serialization and
3807 * deserialization or a proxy, depending on whether the object is
3808 * serializable or marshal by ref. obj must not be in target_domain.
3810 * If the object cannot be represented in target_domain, NULL is
3811 * returned and *exc is set to an appropriate exception.
3814 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3816 MonoObject *deserialized = NULL;
3817 gboolean failure = FALSE;
3821 #ifndef DISABLE_REMOTING
3822 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3823 deserialized = make_transparent_proxy (obj, &failure, exc);
3828 MonoDomain *domain = mono_domain_get ();
3829 MonoObject *serialized;
3831 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3832 serialized = serialize_object (obj, &failure, exc);
3833 mono_domain_set_internal_with_options (target_domain, FALSE);
3835 deserialized = deserialize_object (serialized, &failure, exc);
3836 if (domain != target_domain)
3837 mono_domain_set_internal_with_options (domain, FALSE);
3840 return deserialized;
3843 /* Used in call_unhandled_exception_delegate */
3845 create_unhandled_exception_eventargs (MonoObject *exc)
3849 MonoMethod *method = NULL;
3850 MonoBoolean is_terminating = TRUE;
3853 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3856 mono_class_init (klass);
3858 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3859 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3863 args [1] = &is_terminating;
3865 obj = mono_object_new (mono_domain_get (), klass);
3866 mono_runtime_invoke (method, obj, args, NULL);
3871 /* Used in mono_unhandled_exception */
3873 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3874 MonoObject *e = NULL;
3876 MonoDomain *current_domain = mono_domain_get ();
3878 if (domain != current_domain)
3879 mono_domain_set_internal_with_options (domain, FALSE);
3881 g_assert (domain == mono_object_domain (domain->domain));
3883 if (mono_object_domain (exc) != domain) {
3884 MonoObject *serialization_exc;
3886 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3888 if (serialization_exc) {
3890 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3893 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3894 "System.Runtime.Serialization", "SerializationException",
3895 "Could not serialize unhandled exception.");
3899 g_assert (mono_object_domain (exc) == domain);
3901 pa [0] = domain->domain;
3902 pa [1] = create_unhandled_exception_eventargs (exc);
3903 mono_runtime_delegate_invoke (delegate, pa, &e);
3905 if (domain != current_domain)
3906 mono_domain_set_internal_with_options (current_domain, FALSE);
3910 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3911 if (!mono_error_ok (&error)) {
3912 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3913 mono_error_cleanup (&error);
3915 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3921 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3924 * mono_runtime_unhandled_exception_policy_set:
3925 * @policy: the new policy
3927 * This is a VM internal routine.
3929 * Sets the runtime policy for handling unhandled exceptions.
3932 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3933 runtime_unhandled_exception_policy = policy;
3937 * mono_runtime_unhandled_exception_policy_get:
3939 * This is a VM internal routine.
3941 * Gets the runtime policy for handling unhandled exceptions.
3943 MonoRuntimeUnhandledExceptionPolicy
3944 mono_runtime_unhandled_exception_policy_get (void) {
3945 return runtime_unhandled_exception_policy;
3949 * mono_unhandled_exception:
3950 * @exc: exception thrown
3952 * This is a VM internal routine.
3954 * We call this function when we detect an unhandled exception
3955 * in the default domain.
3957 * It invokes the * UnhandledException event in AppDomain or prints
3958 * a warning to the console
3961 mono_unhandled_exception (MonoObject *exc)
3963 MonoDomain *current_domain = mono_domain_get ();
3964 MonoDomain *root_domain = mono_get_root_domain ();
3965 MonoClassField *field;
3966 MonoObject *current_appdomain_delegate;
3967 MonoObject *root_appdomain_delegate;
3969 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3970 "UnhandledException");
3973 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3974 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3975 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3976 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3977 if (current_domain != root_domain) {
3978 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3980 current_appdomain_delegate = NULL;
3983 /* set exitcode only if we will abort the process */
3984 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3986 mono_environment_exitcode_set (1);
3987 mono_print_unhandled_exception (exc);
3989 if (root_appdomain_delegate) {
3990 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3992 if (current_appdomain_delegate) {
3993 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4000 * mono_runtime_exec_managed_code:
4001 * @domain: Application domain
4002 * @main_func: function to invoke from the execution thread
4003 * @main_args: parameter to the main_func
4005 * Launch a new thread to execute a function
4007 * main_func is called back from the thread with main_args as the
4008 * parameter. The callback function is expected to start Main()
4009 * eventually. This function then waits for all managed threads to
4011 * It is not necesseray anymore to execute managed code in a subthread,
4012 * so this function should not be used anymore by default: just
4013 * execute the code and then call mono_thread_manage ().
4016 mono_runtime_exec_managed_code (MonoDomain *domain,
4017 MonoMainThreadFunc main_func,
4020 mono_thread_create (domain, main_func, main_args);
4022 mono_thread_manage ();
4026 * Execute a standard Main() method (args doesn't contain the
4030 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4035 MonoCustomAttrInfo* cinfo;
4036 gboolean has_stathread_attribute;
4037 MonoInternalThread* thread = mono_thread_internal_current ();
4043 domain = mono_object_domain (args);
4044 if (!domain->entry_assembly) {
4046 MonoAssembly *assembly;
4048 assembly = method->klass->image->assembly;
4049 domain->entry_assembly = assembly;
4050 /* Domains created from another domain already have application_base and configuration_file set */
4051 if (domain->setup->application_base == NULL) {
4052 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4055 if (domain->setup->configuration_file == NULL) {
4056 str = g_strconcat (assembly->image->name, ".config", NULL);
4057 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4059 mono_set_private_bin_path_from_config (domain);
4063 cinfo = mono_custom_attrs_from_method (method);
4065 static MonoClass *stathread_attribute = NULL;
4066 if (!stathread_attribute)
4067 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4068 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4070 mono_custom_attrs_free (cinfo);
4072 has_stathread_attribute = FALSE;
4074 if (has_stathread_attribute) {
4075 thread->apartment_state = ThreadApartmentState_STA;
4077 thread->apartment_state = ThreadApartmentState_MTA;
4079 mono_thread_init_apartment_state ();
4081 /* FIXME: check signature of method */
4082 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4084 res = mono_runtime_invoke (method, NULL, pa, exc);
4086 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4090 mono_environment_exitcode_set (rval);
4092 mono_runtime_invoke (method, NULL, pa, exc);
4096 /* If the return type of Main is void, only
4097 * set the exitcode if an exception was thrown
4098 * (we don't want to blow away an
4099 * explicitly-set exit code)
4102 mono_environment_exitcode_set (rval);
4110 * mono_install_runtime_invoke:
4111 * @func: Function to install
4113 * This is a VM internal routine
4116 mono_install_runtime_invoke (MonoInvokeFunc func)
4118 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4123 * mono_runtime_invoke_array:
4124 * @method: method to invoke
4125 * @obJ: object instance
4126 * @params: arguments to the method
4127 * @exc: exception information.
4129 * Invokes the method represented by @method on the object @obj.
4131 * obj is the 'this' pointer, it should be NULL for static
4132 * methods, a MonoObject* for object instances and a pointer to
4133 * the value type for value types.
4135 * The params array contains the arguments to the method with the
4136 * same convention: MonoObject* pointers for object instances and
4137 * pointers to the value type otherwise. The _invoke_array
4138 * variant takes a C# object[] as the params argument (MonoArray
4139 * *params): in this case the value types are boxed inside the
4140 * respective reference representation.
4142 * From unmanaged code you'll usually use the
4143 * mono_runtime_invoke() variant.
4145 * Note that this function doesn't handle virtual methods for
4146 * you, it will exec the exact method you pass: we still need to
4147 * expose a function to lookup the derived class implementation
4148 * of a virtual method (there are examples of this in the code,
4151 * You can pass NULL as the exc argument if you don't want to
4152 * catch exceptions, otherwise, *exc will be set to the exception
4153 * thrown, if any. if an exception is thrown, you can't use the
4154 * MonoObject* result from the function.
4156 * If the method returns a value type, it is boxed in an object
4160 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4163 MonoMethodSignature *sig = mono_method_signature (method);
4164 gpointer *pa = NULL;
4167 gboolean has_byref_nullables = FALSE;
4169 if (NULL != params) {
4170 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4171 for (i = 0; i < mono_array_length (params); i++) {
4172 MonoType *t = sig->params [i];
4178 case MONO_TYPE_BOOLEAN:
4181 case MONO_TYPE_CHAR:
4190 case MONO_TYPE_VALUETYPE:
4191 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4192 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4193 pa [i] = mono_array_get (params, MonoObject*, i);
4195 has_byref_nullables = TRUE;
4197 /* MS seems to create the objects if a null is passed in */
4198 if (!mono_array_get (params, MonoObject*, i))
4199 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4203 * We can't pass the unboxed vtype byref to the callee, since
4204 * that would mean the callee would be able to modify boxed
4205 * primitive types. So we (and MS) make a copy of the boxed
4206 * object, pass that to the callee, and replace the original
4207 * boxed object in the arg array with the copy.
4209 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4210 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4211 mono_array_setref (params, i, copy);
4214 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4217 case MONO_TYPE_STRING:
4218 case MONO_TYPE_OBJECT:
4219 case MONO_TYPE_CLASS:
4220 case MONO_TYPE_ARRAY:
4221 case MONO_TYPE_SZARRAY:
4223 pa [i] = mono_array_addr (params, MonoObject*, i);
4224 // FIXME: I need to check this code path
4226 pa [i] = mono_array_get (params, MonoObject*, i);
4228 case MONO_TYPE_GENERICINST:
4230 t = &t->data.generic_class->container_class->this_arg;
4232 t = &t->data.generic_class->container_class->byval_arg;
4234 case MONO_TYPE_PTR: {
4237 /* The argument should be an IntPtr */
4238 arg = mono_array_get (params, MonoObject*, i);
4242 g_assert (arg->vtable->klass == mono_defaults.int_class);
4243 pa [i] = ((MonoIntPtr*)arg)->m_value;
4248 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4253 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4256 if (mono_class_is_nullable (method->klass)) {
4257 /* Need to create a boxed vtype instead */
4263 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4267 obj = mono_object_new (mono_domain_get (), method->klass);
4268 g_assert (obj); /*maybe we should raise a TLE instead?*/
4269 #ifndef DISABLE_REMOTING
4270 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4271 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4274 if (method->klass->valuetype)
4275 o = mono_object_unbox (obj);
4278 } else if (method->klass->valuetype) {
4279 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4282 mono_runtime_invoke (method, o, pa, exc);
4285 if (mono_class_is_nullable (method->klass)) {
4286 MonoObject *nullable;
4288 /* Convert the unboxed vtype into a Nullable structure */
4289 nullable = mono_object_new (mono_domain_get (), method->klass);
4291 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4292 obj = mono_object_unbox (nullable);
4295 /* obj must be already unboxed if needed */
4296 res = mono_runtime_invoke (method, obj, pa, exc);
4298 if (sig->ret->type == MONO_TYPE_PTR) {
4299 MonoClass *pointer_class;
4300 static MonoMethod *box_method;
4302 MonoObject *box_exc;
4305 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4306 * convert it to a Pointer object.
4308 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4310 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4312 g_assert (res->vtable->klass == mono_defaults.int_class);
4313 box_args [0] = ((MonoIntPtr*)res)->m_value;
4314 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4315 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4316 g_assert (!box_exc);
4319 if (has_byref_nullables) {
4321 * The runtime invoke wrapper already converted byref nullables back,
4322 * and stored them in pa, we just need to copy them back to the
4325 for (i = 0; i < mono_array_length (params); i++) {
4326 MonoType *t = sig->params [i];
4328 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4329 mono_array_setref (params, i, pa [i]);
4338 arith_overflow (void)
4340 mono_raise_exception (mono_get_exception_overflow ());
4344 * mono_object_allocate:
4345 * @size: number of bytes to allocate
4347 * This is a very simplistic routine until we have our GC-aware
4350 * Returns: an allocated object of size @size, or NULL on failure.
4352 static inline void *
4353 mono_object_allocate (size_t size, MonoVTable *vtable)
4356 mono_stats.new_object_count++;
4357 ALLOC_OBJECT (o, vtable, size);
4363 * mono_object_allocate_ptrfree:
4364 * @size: number of bytes to allocate
4366 * Note that the memory allocated is not zeroed.
4367 * Returns: an allocated object of size @size, or NULL on failure.
4369 static inline void *
4370 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4373 mono_stats.new_object_count++;
4374 ALLOC_PTRFREE (o, vtable, size);
4378 static inline void *
4379 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4382 ALLOC_TYPED (o, size, vtable);
4383 mono_stats.new_object_count++;
4390 * @klass: the class of the object that we want to create
4392 * Returns: a newly created object whose definition is
4393 * looked up using @klass. This will not invoke any constructors,
4394 * so the consumer of this routine has to invoke any constructors on
4395 * its own to initialize the object.
4397 * It returns NULL on failure.
4400 mono_object_new (MonoDomain *domain, MonoClass *klass)
4404 MONO_ARCH_SAVE_REGS;
4405 vtable = mono_class_vtable (domain, klass);
4408 return mono_object_new_specific (vtable);
4412 * mono_object_new_pinned:
4414 * Same as mono_object_new, but the returned object will be pinned.
4415 * For SGEN, these objects will only be freed at appdomain unload.
4418 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4422 MONO_ARCH_SAVE_REGS;
4423 vtable = mono_class_vtable (domain, klass);
4428 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4430 return mono_object_new_specific (vtable);
4435 * mono_object_new_specific:
4436 * @vtable: the vtable of the object that we want to create
4438 * Returns: A newly created object with class and domain specified
4442 mono_object_new_specific (MonoVTable *vtable)
4446 MONO_ARCH_SAVE_REGS;
4448 /* check for is_com_object for COM Interop */
4449 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4452 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4455 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4458 mono_class_init (klass);
4460 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4462 vtable->domain->create_proxy_for_type_method = im;
4465 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4467 o = mono_runtime_invoke (im, NULL, pa, NULL);
4468 if (o != NULL) return o;
4471 return mono_object_new_alloc_specific (vtable);
4475 mono_object_new_alloc_specific (MonoVTable *vtable)
4479 if (!vtable->klass->has_references) {
4480 o = mono_object_new_ptrfree (vtable);
4481 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4482 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4484 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4485 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4487 if (G_UNLIKELY (vtable->klass->has_finalize))
4488 mono_object_register_finalizer (o);
4490 if (G_UNLIKELY (profile_allocs))
4491 mono_profiler_allocation (o, vtable->klass);
4496 mono_object_new_fast (MonoVTable *vtable)
4499 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4504 mono_object_new_ptrfree (MonoVTable *vtable)
4507 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4508 #if NEED_TO_ZERO_PTRFREE
4509 /* an inline memset is much faster for the common vcase of small objects
4510 * note we assume the allocated size is a multiple of sizeof (void*).
4512 if (vtable->klass->instance_size < 128) {
4514 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4515 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4521 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4528 mono_object_new_ptrfree_box (MonoVTable *vtable)
4531 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4532 /* the object will be boxed right away, no need to memzero it */
4537 * mono_class_get_allocation_ftn:
4539 * @for_box: the object will be used for boxing
4540 * @pass_size_in_words:
4542 * Return the allocation function appropriate for the given class.
4546 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4548 *pass_size_in_words = FALSE;
4550 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4551 profile_allocs = FALSE;
4553 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4554 return mono_object_new_specific;
4556 if (!vtable->klass->has_references) {
4557 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4559 return mono_object_new_ptrfree_box;
4560 return mono_object_new_ptrfree;
4563 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4565 return mono_object_new_fast;
4568 * FIXME: This is actually slower than mono_object_new_fast, because
4569 * of the overhead of parameter passing.
4572 *pass_size_in_words = TRUE;
4573 #ifdef GC_REDIRECT_TO_LOCAL
4574 return GC_local_gcj_fast_malloc;
4576 return GC_gcj_fast_malloc;
4581 return mono_object_new_specific;
4585 * mono_object_new_from_token:
4586 * @image: Context where the type_token is hosted
4587 * @token: a token of the type that we want to create
4589 * Returns: A newly created object whose definition is
4590 * looked up using @token in the @image image
4593 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4597 class = mono_class_get (image, token);
4599 return mono_object_new (domain, class);
4604 * mono_object_clone:
4605 * @obj: the object to clone
4607 * Returns: A newly created object who is a shallow copy of @obj
4610 mono_object_clone (MonoObject *obj)
4613 int size = obj->vtable->klass->instance_size;
4615 if (obj->vtable->klass->rank)
4616 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4618 o = mono_object_allocate (size, obj->vtable);
4620 if (obj->vtable->klass->has_references) {
4621 mono_gc_wbarrier_object_copy (o, obj);
4623 int size = obj->vtable->klass->instance_size;
4624 /* do not copy the sync state */
4625 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4627 if (G_UNLIKELY (profile_allocs))
4628 mono_profiler_allocation (o, obj->vtable->klass);
4630 if (obj->vtable->klass->has_finalize)
4631 mono_object_register_finalizer (o);
4636 * mono_array_full_copy:
4637 * @src: source array to copy
4638 * @dest: destination array
4640 * Copies the content of one array to another with exactly the same type and size.
4643 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4646 MonoClass *klass = src->obj.vtable->klass;
4648 MONO_ARCH_SAVE_REGS;
4650 g_assert (klass == dest->obj.vtable->klass);
4652 size = mono_array_length (src);
4653 g_assert (size == mono_array_length (dest));
4654 size *= mono_array_element_size (klass);
4656 if (klass->element_class->valuetype) {
4657 if (klass->element_class->has_references)
4658 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4660 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4662 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4665 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4670 * mono_array_clone_in_domain:
4671 * @domain: the domain in which the array will be cloned into
4672 * @array: the array to clone
4674 * This routine returns a copy of the array that is hosted on the
4675 * specified MonoDomain.
4678 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4683 MonoClass *klass = array->obj.vtable->klass;
4685 MONO_ARCH_SAVE_REGS;
4687 if (array->bounds == NULL) {
4688 size = mono_array_length (array);
4689 o = mono_array_new_full (domain, klass, &size, NULL);
4691 size *= mono_array_element_size (klass);
4693 if (klass->element_class->valuetype) {
4694 if (klass->element_class->has_references)
4695 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4697 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4699 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4702 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4707 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4708 size = mono_array_element_size (klass);
4709 for (i = 0; i < klass->rank; ++i) {
4710 sizes [i] = array->bounds [i].length;
4711 size *= array->bounds [i].length;
4712 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4714 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4716 if (klass->element_class->valuetype) {
4717 if (klass->element_class->has_references)
4718 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4720 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4722 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4725 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4733 * @array: the array to clone
4735 * Returns: A newly created array who is a shallow copy of @array
4738 mono_array_clone (MonoArray *array)
4740 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4743 /* helper macros to check for overflow when calculating the size of arrays */
4744 #ifdef MONO_BIG_ARRAYS
4745 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4746 #define MYGUINT_MAX MYGUINT64_MAX
4747 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4748 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4749 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4750 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4751 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4753 #define MYGUINT32_MAX 4294967295U
4754 #define MYGUINT_MAX MYGUINT32_MAX
4755 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4756 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4757 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4758 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4759 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4763 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4767 byte_len = mono_array_element_size (class);
4768 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4771 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4773 byte_len += sizeof (MonoArray);
4781 * mono_array_new_full:
4782 * @domain: domain where the object is created
4783 * @array_class: array class
4784 * @lengths: lengths for each dimension in the array
4785 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4787 * This routine creates a new array objects with the given dimensions,
4788 * lower bounds and type.
4791 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4793 uintptr_t byte_len, len, bounds_size;
4796 MonoArrayBounds *bounds;
4800 if (!array_class->inited)
4801 mono_class_init (array_class);
4805 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4806 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4808 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4812 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4814 for (i = 0; i < array_class->rank; ++i) {
4815 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4817 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4818 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4823 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4824 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4828 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4829 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4830 byte_len = (byte_len + 3) & ~3;
4831 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4832 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4833 byte_len += bounds_size;
4836 * Following three lines almost taken from mono_object_new ():
4837 * they need to be kept in sync.
4839 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4840 #ifndef HAVE_SGEN_GC
4841 if (!array_class->has_references) {
4842 o = mono_object_allocate_ptrfree (byte_len, vtable);
4843 #if NEED_TO_ZERO_PTRFREE
4844 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4846 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4847 o = mono_object_allocate_spec (byte_len, vtable);
4849 o = mono_object_allocate (byte_len, vtable);
4852 array = (MonoArray*)o;
4853 array->max_length = len;
4856 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4857 array->bounds = bounds;
4861 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4863 o = mono_gc_alloc_vector (vtable, byte_len, len);
4864 array = (MonoArray*)o;
4865 mono_stats.new_object_count++;
4867 bounds = array->bounds;
4871 for (i = 0; i < array_class->rank; ++i) {
4872 bounds [i].length = lengths [i];
4874 bounds [i].lower_bound = lower_bounds [i];
4878 if (G_UNLIKELY (profile_allocs))
4879 mono_profiler_allocation (o, array_class);
4886 * @domain: domain where the object is created
4887 * @eclass: element class
4888 * @n: number of array elements
4890 * This routine creates a new szarray with @n elements of type @eclass.
4893 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4897 MONO_ARCH_SAVE_REGS;
4899 ac = mono_array_class_get (eclass, 1);
4902 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4906 * mono_array_new_specific:
4907 * @vtable: a vtable in the appropriate domain for an initialized class
4908 * @n: number of array elements
4910 * This routine is a fast alternative to mono_array_new() for code which
4911 * can be sure about the domain it operates in.
4914 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4920 MONO_ARCH_SAVE_REGS;
4922 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4927 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4928 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4931 #ifndef HAVE_SGEN_GC
4932 if (!vtable->klass->has_references) {
4933 o = mono_object_allocate_ptrfree (byte_len, vtable);
4934 #if NEED_TO_ZERO_PTRFREE
4935 ((MonoArray*)o)->bounds = NULL;
4936 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4938 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4939 o = mono_object_allocate_spec (byte_len, vtable);
4941 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4942 o = mono_object_allocate (byte_len, vtable);
4945 ao = (MonoArray *)o;
4948 o = mono_gc_alloc_vector (vtable, byte_len, n);
4950 mono_stats.new_object_count++;
4953 if (G_UNLIKELY (profile_allocs))
4954 mono_profiler_allocation (o, vtable->klass);
4960 * mono_string_new_utf16:
4961 * @text: a pointer to an utf16 string
4962 * @len: the length of the string
4964 * Returns: A newly created string object which contains @text.
4967 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4971 s = mono_string_new_size (domain, len);
4972 g_assert (s != NULL);
4974 memcpy (mono_string_chars (s), text, len * 2);
4980 * mono_string_new_size:
4981 * @text: a pointer to an utf16 string
4982 * @len: the length of the string
4984 * Returns: A newly created string object of @len
4987 mono_string_new_size (MonoDomain *domain, gint32 len)
4993 /* check for overflow */
4994 if (len < 0 || len > ((SIZE_MAX - sizeof (MonoString) - 2) / 2))
4995 mono_gc_out_of_memory (-1);
4997 size = (sizeof (MonoString) + ((len + 1) * 2));
4998 g_assert (size > 0);
5000 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5003 #ifndef HAVE_SGEN_GC
5004 s = mono_object_allocate_ptrfree (size, vtable);
5008 s = mono_gc_alloc_string (vtable, size, len);
5010 #if NEED_TO_ZERO_PTRFREE
5013 if (G_UNLIKELY (profile_allocs))
5014 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5020 * mono_string_new_len:
5021 * @text: a pointer to an utf8 string
5022 * @length: number of bytes in @text to consider
5024 * Returns: A newly created string object which contains @text.
5027 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5029 GError *error = NULL;
5030 MonoString *o = NULL;
5032 glong items_written;
5034 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5037 o = mono_string_new_utf16 (domain, ut, items_written);
5039 g_error_free (error);
5048 * @text: a pointer to an utf8 string
5050 * Returns: A newly created string object which contains @text.
5053 mono_string_new (MonoDomain *domain, const char *text)
5055 GError *error = NULL;
5056 MonoString *o = NULL;
5058 glong items_written;
5063 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5066 o = mono_string_new_utf16 (domain, ut, items_written);
5068 g_error_free (error);
5071 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5076 MonoString *o = NULL;
5078 if (!g_utf8_validate (text, -1, &end))
5081 len = g_utf8_strlen (text, -1);
5082 o = mono_string_new_size (domain, len);
5083 str = mono_string_chars (o);
5085 while (text < end) {
5086 *str++ = g_utf8_get_char (text);
5087 text = g_utf8_next_char (text);
5094 * mono_string_new_wrapper:
5095 * @text: pointer to utf8 characters.
5097 * Helper function to create a string object from @text in the current domain.
5100 mono_string_new_wrapper (const char *text)
5102 MonoDomain *domain = mono_domain_get ();
5104 MONO_ARCH_SAVE_REGS;
5107 return mono_string_new (domain, text);
5114 * @class: the class of the value
5115 * @value: a pointer to the unboxed data
5117 * Returns: A newly created object which contains @value.
5120 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5126 g_assert (class->valuetype);
5127 if (mono_class_is_nullable (class))
5128 return mono_nullable_box (value, class);
5130 vtable = mono_class_vtable (domain, class);
5133 size = mono_class_instance_size (class);
5134 res = mono_object_new_alloc_specific (vtable);
5135 if (G_UNLIKELY (profile_allocs))
5136 mono_profiler_allocation (res, class);
5138 size = size - sizeof (MonoObject);
5141 g_assert (size == mono_class_value_size (class, NULL));
5142 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5144 #if NO_UNALIGNED_ACCESS
5145 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5149 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5152 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5155 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5158 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5161 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5165 if (class->has_finalize)
5166 mono_object_register_finalizer (res);
5172 * @dest: destination pointer
5173 * @src: source pointer
5174 * @klass: a valuetype class
5176 * Copy a valuetype from @src to @dest. This function must be used
5177 * when @klass contains references fields.
5180 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5182 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5186 * mono_value_copy_array:
5187 * @dest: destination array
5188 * @dest_idx: index in the @dest array
5189 * @src: source pointer
5190 * @count: number of items
5192 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5193 * This function must be used when @klass contains references fields.
5194 * Overlap is handled.
5197 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5199 int size = mono_array_element_size (dest->obj.vtable->klass);
5200 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5201 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5202 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5206 * mono_object_get_domain:
5207 * @obj: object to query
5209 * Returns: the MonoDomain where the object is hosted
5212 mono_object_get_domain (MonoObject *obj)
5214 return mono_object_domain (obj);
5218 * mono_object_get_class:
5219 * @obj: object to query
5221 * Returns: the MonOClass of the object.
5224 mono_object_get_class (MonoObject *obj)
5226 return mono_object_class (obj);
5229 * mono_object_get_size:
5230 * @o: object to query
5232 * Returns: the size, in bytes, of @o
5235 mono_object_get_size (MonoObject* o)
5237 MonoClass* klass = mono_object_class (o);
5238 if (klass == mono_defaults.string_class) {
5239 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5240 } else if (o->vtable->rank) {
5241 MonoArray *array = (MonoArray*)o;
5242 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5243 if (array->bounds) {
5246 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5250 return mono_class_instance_size (klass);
5255 * mono_object_unbox:
5256 * @obj: object to unbox
5258 * Returns: a pointer to the start of the valuetype boxed in this
5261 * This method will assert if the object passed is not a valuetype.
5264 mono_object_unbox (MonoObject *obj)
5266 /* add assert for valuetypes? */
5267 g_assert (obj->vtable->klass->valuetype);
5268 return ((char*)obj) + sizeof (MonoObject);
5272 * mono_object_isinst:
5274 * @klass: a pointer to a class
5276 * Returns: @obj if @obj is derived from @klass
5279 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5282 mono_class_init (klass);
5284 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5285 return mono_object_isinst_mbyref (obj, klass);
5290 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5294 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5303 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5304 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5308 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5309 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5312 MonoClass *oklass = vt->klass;
5313 if (mono_class_is_transparent_proxy (oklass))
5314 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5316 mono_class_setup_supertypes (klass);
5317 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5320 #ifndef DISABLE_REMOTING
5321 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5323 MonoDomain *domain = mono_domain_get ();
5325 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5326 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5327 MonoMethod *im = NULL;
5330 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5331 im = mono_object_get_virtual_method (rp, im);
5334 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5337 res = mono_runtime_invoke (im, rp, pa, NULL);
5339 if (*(MonoBoolean *) mono_object_unbox(res)) {
5340 /* Update the vtable of the remote type, so it can safely cast to this new type */
5341 mono_upgrade_remote_class (domain, obj, klass);
5345 #endif /* DISABLE_REMOTING */
5350 * mono_object_castclass_mbyref:
5352 * @klass: a pointer to a class
5354 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5357 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5359 if (!obj) return NULL;
5360 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5362 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5364 "InvalidCastException"));
5369 MonoDomain *orig_domain;
5375 str_lookup (MonoDomain *domain, gpointer user_data)
5377 LDStrInfo *info = user_data;
5378 if (info->res || domain == info->orig_domain)
5380 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5386 mono_string_get_pinned (MonoString *str)
5390 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5391 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5393 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5394 news->length = mono_string_length (str);
5400 #define mono_string_get_pinned(str) (str)
5404 mono_string_is_interned_lookup (MonoString *str, int insert)
5406 MonoGHashTable *ldstr_table;
5410 domain = ((MonoObject *)str)->vtable->domain;
5411 ldstr_table = domain->ldstr_table;
5413 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5418 str = mono_string_get_pinned (str);
5420 mono_g_hash_table_insert (ldstr_table, str, str);
5424 LDStrInfo ldstr_info;
5425 ldstr_info.orig_domain = domain;
5426 ldstr_info.ins = str;
5427 ldstr_info.res = NULL;
5429 mono_domain_foreach (str_lookup, &ldstr_info);
5430 if (ldstr_info.res) {
5432 * the string was already interned in some other domain:
5433 * intern it in the current one as well.
5435 mono_g_hash_table_insert (ldstr_table, str, str);
5445 * mono_string_is_interned:
5446 * @o: String to probe
5448 * Returns whether the string has been interned.
5451 mono_string_is_interned (MonoString *o)
5453 return mono_string_is_interned_lookup (o, FALSE);
5457 * mono_string_intern:
5458 * @o: String to intern
5460 * Interns the string passed.
5461 * Returns: The interned string.
5464 mono_string_intern (MonoString *str)
5466 return mono_string_is_interned_lookup (str, TRUE);
5471 * @domain: the domain where the string will be used.
5472 * @image: a metadata context
5473 * @idx: index into the user string table.
5475 * Implementation for the ldstr opcode.
5476 * Returns: a loaded string from the @image/@idx combination.
5479 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5481 MONO_ARCH_SAVE_REGS;
5483 if (image->dynamic) {
5484 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5487 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5488 return NULL; /*FIXME we should probably be raising an exception here*/
5489 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5494 * mono_ldstr_metadata_sig
5495 * @domain: the domain for the string
5496 * @sig: the signature of a metadata string
5498 * Returns: a MonoString for a string stored in the metadata
5501 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5503 const char *str = sig;
5504 MonoString *o, *interned;
5507 len2 = mono_metadata_decode_blob_size (str, &str);
5510 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5511 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5514 guint16 *p2 = (guint16*)mono_string_chars (o);
5515 for (i = 0; i < len2; ++i) {
5516 *p2 = GUINT16_FROM_LE (*p2);
5522 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5524 /* o will get garbage collected */
5528 o = mono_string_get_pinned (o);
5530 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5537 * mono_string_to_utf8:
5538 * @s: a System.String
5540 * Returns the UTF8 representation for @s.
5541 * The resulting buffer needs to be freed with mono_free().
5543 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5546 mono_string_to_utf8 (MonoString *s)
5549 char *result = mono_string_to_utf8_checked (s, &error);
5551 if (!mono_error_ok (&error))
5552 mono_error_raise_exception (&error);
5557 * mono_string_to_utf8_checked:
5558 * @s: a System.String
5559 * @error: a MonoError.
5561 * Converts a MonoString to its UTF8 representation. May fail; check
5562 * @error to determine whether the conversion was successful.
5563 * The resulting buffer should be freed with mono_free().
5566 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5570 GError *gerror = NULL;
5572 mono_error_init (error);
5578 return g_strdup ("");
5580 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5582 mono_error_set_argument (error, "string", "%s", gerror->message);
5583 g_error_free (gerror);
5586 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5587 if (s->length > written) {
5588 /* allocate the total length and copy the part of the string that has been converted */
5589 char *as2 = g_malloc0 (s->length);
5590 memcpy (as2, as, written);
5599 * mono_string_to_utf8_ignore:
5602 * Converts a MonoString to its UTF8 representation. Will ignore
5603 * invalid surrogate pairs.
5604 * The resulting buffer should be freed with mono_free().
5608 mono_string_to_utf8_ignore (MonoString *s)
5617 return g_strdup ("");
5619 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5621 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5622 if (s->length > written) {
5623 /* allocate the total length and copy the part of the string that has been converted */
5624 char *as2 = g_malloc0 (s->length);
5625 memcpy (as2, as, written);
5634 * mono_string_to_utf8_image_ignore:
5635 * @s: a System.String
5637 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5640 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5642 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5646 * mono_string_to_utf8_mp_ignore:
5647 * @s: a System.String
5649 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5652 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5654 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5659 * mono_string_to_utf16:
5662 * Return an null-terminated array of the utf-16 chars
5663 * contained in @s. The result must be freed with g_free().
5664 * This is a temporary helper until our string implementation
5665 * is reworked to always include the null terminating char.
5668 mono_string_to_utf16 (MonoString *s)
5675 as = g_malloc ((s->length * 2) + 2);
5676 as [(s->length * 2)] = '\0';
5677 as [(s->length * 2) + 1] = '\0';
5680 return (gunichar2 *)(as);
5683 memcpy (as, mono_string_chars(s), s->length * 2);
5684 return (gunichar2 *)(as);
5688 * mono_string_from_utf16:
5689 * @data: the UTF16 string (LPWSTR) to convert
5691 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5693 * Returns: a MonoString.
5696 mono_string_from_utf16 (gunichar2 *data)
5698 MonoDomain *domain = mono_domain_get ();
5704 while (data [len]) len++;
5706 return mono_string_new_utf16 (domain, data, len);
5711 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5718 r = mono_string_to_utf8_ignore (s);
5720 r = mono_string_to_utf8_checked (s, error);
5721 if (!mono_error_ok (error))
5728 len = strlen (r) + 1;
5730 mp_s = mono_mempool_alloc (mp, len);
5732 mp_s = mono_image_alloc (image, len);
5734 memcpy (mp_s, r, len);
5742 * mono_string_to_utf8_image:
5743 * @s: a System.String
5745 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5748 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5750 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5754 * mono_string_to_utf8_mp:
5755 * @s: a System.String
5757 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5760 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5762 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5766 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5769 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5771 eh_callbacks = *cbs;
5774 MonoRuntimeExceptionHandlingCallbacks *
5775 mono_get_eh_callbacks (void)
5777 return &eh_callbacks;
5781 * mono_raise_exception:
5782 * @ex: exception object
5784 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5787 mono_raise_exception (MonoException *ex)
5790 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5791 * that will cause gcc to omit the function epilog, causing problems when
5792 * the JIT tries to walk the stack, since the return address on the stack
5793 * will point into the next function in the executable, not this one.
5795 eh_callbacks.mono_raise_exception (ex);
5799 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5801 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5805 * mono_wait_handle_new:
5806 * @domain: Domain where the object will be created
5807 * @handle: Handle for the wait handle
5809 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5812 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5814 MonoWaitHandle *res;
5815 gpointer params [1];
5816 static MonoMethod *handle_set;
5818 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5820 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5822 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5824 params [0] = &handle;
5825 mono_runtime_invoke (handle_set, res, params, NULL);
5831 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5833 static MonoClassField *f_os_handle;
5834 static MonoClassField *f_safe_handle;
5836 if (!f_os_handle && !f_safe_handle) {
5837 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5838 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5843 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5847 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5854 mono_runtime_capture_context (MonoDomain *domain)
5856 RuntimeInvokeFunction runtime_invoke;
5858 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5859 MonoMethod *method = mono_get_context_capture_method ();
5860 MonoMethod *wrapper;
5863 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5864 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5865 domain->capture_context_method = mono_compile_method (method);
5868 runtime_invoke = domain->capture_context_runtime_invoke;
5870 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5873 * mono_async_result_new:
5874 * @domain:domain where the object will be created.
5875 * @handle: wait handle.
5876 * @state: state to pass to AsyncResult
5877 * @data: C closure data.
5879 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5880 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5884 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5886 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5887 MonoObject *context = mono_runtime_capture_context (domain);
5888 /* we must capture the execution context from the original thread */
5890 MONO_OBJECT_SETREF (res, execution_context, context);
5891 /* note: result may be null if the flow is suppressed */
5895 MONO_OBJECT_SETREF (res, object_data, object_data);
5896 MONO_OBJECT_SETREF (res, async_state, state);
5898 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5900 res->sync_completed = FALSE;
5901 res->completed = FALSE;
5907 mono_message_init (MonoDomain *domain,
5908 MonoMethodMessage *this,
5909 MonoReflectionMethod *method,
5910 MonoArray *out_args)
5912 static MonoClass *object_array_klass;
5913 static MonoClass *byte_array_klass;
5914 static MonoClass *string_array_klass;
5915 MonoMethodSignature *sig = mono_method_signature (method->method);
5921 if (!object_array_klass) {
5924 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5926 byte_array_klass = klass;
5928 klass = mono_array_class_get (mono_defaults.string_class, 1);
5930 string_array_klass = klass;
5932 klass = mono_array_class_get (mono_defaults.object_class, 1);
5935 mono_atomic_store_release (&object_array_klass, klass);
5938 MONO_OBJECT_SETREF (this, method, method);
5940 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5941 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5942 this->async_result = NULL;
5943 this->call_type = CallType_Sync;
5945 names = g_new (char *, sig->param_count);
5946 mono_method_get_param_names (method->method, (const char **) names);
5947 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5949 for (i = 0; i < sig->param_count; i++) {
5950 name = mono_string_new (domain, names [i]);
5951 mono_array_setref (this->names, i, name);
5955 for (i = 0, j = 0; i < sig->param_count; i++) {
5956 if (sig->params [i]->byref) {
5958 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5959 mono_array_setref (this->args, i, arg);
5963 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5967 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5970 mono_array_set (this->arg_types, guint8, i, arg_type);
5974 #ifndef DISABLE_REMOTING
5976 * mono_remoting_invoke:
5977 * @real_proxy: pointer to a RealProxy object
5978 * @msg: The MonoMethodMessage to execute
5979 * @exc: used to store exceptions
5980 * @out_args: used to store output arguments
5982 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5983 * IMessage interface and it is not trivial to extract results from there. So
5984 * we call an helper method PrivateInvoke instead of calling
5985 * RealProxy::Invoke() directly.
5987 * Returns: the result object.
5990 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5991 MonoObject **exc, MonoArray **out_args)
5993 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5996 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5999 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6001 real_proxy->vtable->domain->private_invoke_method = im;
6004 pa [0] = real_proxy;
6009 return mono_runtime_invoke (im, NULL, pa, exc);
6014 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6015 MonoObject **exc, MonoArray **out_args)
6017 static MonoClass *object_array_klass;
6020 MonoMethodSignature *sig;
6022 int i, j, outarg_count = 0;
6024 #ifndef DISABLE_REMOTING
6025 if (target && mono_object_is_transparent_proxy (target)) {
6026 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6027 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6028 target = tp->rp->unwrapped_server;
6030 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6035 domain = mono_domain_get ();
6036 method = msg->method->method;
6037 sig = mono_method_signature (method);
6039 for (i = 0; i < sig->param_count; i++) {
6040 if (sig->params [i]->byref)
6044 if (!object_array_klass) {
6047 klass = mono_array_class_get (mono_defaults.object_class, 1);
6050 mono_memory_barrier ();
6051 object_array_klass = klass;
6054 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6055 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6058 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6060 for (i = 0, j = 0; i < sig->param_count; i++) {
6061 if (sig->params [i]->byref) {
6063 arg = mono_array_get (msg->args, gpointer, i);
6064 mono_array_setref (*out_args, j, arg);
6073 * mono_object_to_string:
6075 * @exc: Any exception thrown by ToString (). May be NULL.
6077 * Returns: the result of calling ToString () on an object.
6080 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6082 static MonoMethod *to_string = NULL;
6089 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6091 method = mono_object_get_virtual_method (obj, to_string);
6093 // Unbox value type if needed
6094 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6095 target = mono_object_unbox (obj);
6098 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6102 * mono_print_unhandled_exception:
6103 * @exc: The exception
6105 * Prints the unhandled exception.
6108 mono_print_unhandled_exception (MonoObject *exc)
6111 char *message = (char*)"";
6112 gboolean free_message = FALSE;
6115 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6116 message = g_strdup ("OutOfMemoryException");
6117 free_message = TRUE;
6120 if (((MonoException*)exc)->native_trace_ips) {
6121 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6122 free_message = TRUE;
6124 MonoObject *other_exc = NULL;
6125 str = mono_object_to_string (exc, &other_exc);
6127 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6128 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6130 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6131 original_backtrace, nested_backtrace);
6133 g_free (original_backtrace);
6134 g_free (nested_backtrace);
6135 free_message = TRUE;
6137 message = mono_string_to_utf8_checked (str, &error);
6138 if (!mono_error_ok (&error)) {
6139 mono_error_cleanup (&error);
6140 message = (char *) "";
6142 free_message = TRUE;
6149 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6150 * exc->vtable->klass->name, message);
6152 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6159 * mono_delegate_ctor:
6160 * @this: pointer to an uninitialized delegate object
6161 * @target: target object
6162 * @addr: pointer to native code
6165 * Initialize a delegate and sets a specific method, not the one
6166 * associated with addr. This is useful when sharing generic code.
6167 * In that case addr will most probably not be associated with the
6168 * correct instantiation of the method.
6171 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6173 MonoDelegate *delegate = (MonoDelegate *)this;
6180 delegate->method = method;
6182 class = this->vtable->klass;
6183 mono_stats.delegate_creations++;
6185 #ifndef DISABLE_REMOTING
6186 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6188 method = mono_marshal_get_remoting_invoke (method);
6189 delegate->method_ptr = mono_compile_method (method);
6190 MONO_OBJECT_SETREF (delegate, target, target);
6194 delegate->method_ptr = addr;
6195 MONO_OBJECT_SETREF (delegate, target, target);
6198 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6202 * mono_delegate_ctor:
6203 * @this: pointer to an uninitialized delegate object
6204 * @target: target object
6205 * @addr: pointer to native code
6207 * This is used to initialize a delegate.
6210 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6212 MonoDomain *domain = mono_domain_get ();
6214 MonoMethod *method = NULL;
6218 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6220 if (!ji && domain != mono_get_root_domain ())
6221 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6223 method = mono_jit_info_get_method (ji);
6224 g_assert (!method->klass->generic_container);
6227 mono_delegate_ctor_with_method (this, target, addr, method);
6231 * mono_method_call_message_new:
6232 * @method: method to encapsulate
6233 * @params: parameters to the method
6234 * @invoke: optional, delegate invoke.
6235 * @cb: async callback delegate.
6236 * @state: state passed to the async callback.
6238 * Translates arguments pointers into a MonoMethodMessage.
6241 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6242 MonoDelegate **cb, MonoObject **state)
6244 MonoDomain *domain = mono_domain_get ();
6245 MonoMethodSignature *sig = mono_method_signature (method);
6246 MonoMethodMessage *msg;
6249 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6252 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6253 count = sig->param_count - 2;
6255 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6256 count = sig->param_count;
6259 for (i = 0; i < count; i++) {
6264 if (sig->params [i]->byref)
6265 vpos = *((gpointer *)params [i]);
6269 type = sig->params [i]->type;
6270 class = mono_class_from_mono_type (sig->params [i]);
6272 if (class->valuetype)
6273 arg = mono_value_box (domain, class, vpos);
6275 arg = *((MonoObject **)vpos);
6277 mono_array_setref (msg->args, i, arg);
6280 if (cb != NULL && state != NULL) {
6281 *cb = *((MonoDelegate **)params [i]);
6283 *state = *((MonoObject **)params [i]);
6290 * mono_method_return_message_restore:
6292 * Restore results from message based processing back to arguments pointers
6295 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6297 MonoMethodSignature *sig = mono_method_signature (method);
6298 int i, j, type, size, out_len;
6300 if (out_args == NULL)
6302 out_len = mono_array_length (out_args);
6306 for (i = 0, j = 0; i < sig->param_count; i++) {
6307 MonoType *pt = sig->params [i];
6312 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6314 arg = mono_array_get (out_args, gpointer, j);
6317 g_assert (type != MONO_TYPE_VOID);
6319 if (MONO_TYPE_IS_REFERENCE (pt)) {
6320 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6323 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6324 size = mono_class_value_size (class, NULL);
6325 if (class->has_references)
6326 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6328 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6330 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6331 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6340 #ifndef DISABLE_REMOTING
6343 * mono_load_remote_field:
6344 * @this: pointer to an object
6345 * @klass: klass of the object containing @field
6346 * @field: the field to load
6347 * @res: a storage to store the result
6349 * This method is called by the runtime on attempts to load fields of
6350 * transparent proxy objects. @this points to such TP, @klass is the class of
6351 * the object containing @field. @res is a storage location which can be
6352 * used to store the result.
6354 * Returns: an address pointing to the value of field.
6357 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6359 static MonoMethod *getter = NULL;
6360 MonoDomain *domain = mono_domain_get ();
6361 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6362 MonoClass *field_class;
6363 MonoMethodMessage *msg;
6364 MonoArray *out_args;
6368 g_assert (mono_object_is_transparent_proxy (this));
6369 g_assert (res != NULL);
6371 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6372 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6377 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6381 field_class = mono_class_from_mono_type (field->type);
6383 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6384 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6385 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6387 full_name = mono_type_get_full_name (klass);
6388 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6389 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6392 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6394 if (exc) mono_raise_exception ((MonoException *)exc);
6396 if (mono_array_length (out_args) == 0)
6399 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6401 if (field_class->valuetype) {
6402 return ((char *)*res) + sizeof (MonoObject);
6408 * mono_load_remote_field_new:
6413 * Missing documentation.
6416 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6418 static MonoMethod *getter = NULL;
6419 MonoDomain *domain = mono_domain_get ();
6420 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6421 MonoClass *field_class;
6422 MonoMethodMessage *msg;
6423 MonoArray *out_args;
6424 MonoObject *exc, *res;
6427 g_assert (mono_object_is_transparent_proxy (this));
6429 field_class = mono_class_from_mono_type (field->type);
6431 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6433 if (field_class->valuetype) {
6434 res = mono_object_new (domain, field_class);
6435 val = ((gchar *) res) + sizeof (MonoObject);
6439 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6444 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6448 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6449 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6451 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6453 full_name = mono_type_get_full_name (klass);
6454 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6455 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6458 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6460 if (exc) mono_raise_exception ((MonoException *)exc);
6462 if (mono_array_length (out_args) == 0)
6465 res = mono_array_get (out_args, MonoObject *, 0);
6471 * mono_store_remote_field:
6472 * @this: pointer to an object
6473 * @klass: klass of the object containing @field
6474 * @field: the field to load
6475 * @val: the value/object to store
6477 * This method is called by the runtime on attempts to store fields of
6478 * transparent proxy objects. @this points to such TP, @klass is the class of
6479 * the object containing @field. @val is the new value to store in @field.
6482 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6484 static MonoMethod *setter = NULL;
6485 MonoDomain *domain = mono_domain_get ();
6486 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6487 MonoClass *field_class;
6488 MonoMethodMessage *msg;
6489 MonoArray *out_args;
6494 g_assert (mono_object_is_transparent_proxy (this));
6496 field_class = mono_class_from_mono_type (field->type);
6498 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6499 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6500 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6505 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6509 if (field_class->valuetype)
6510 arg = mono_value_box (domain, field_class, val);
6512 arg = *((MonoObject **)val);
6515 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6516 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6518 full_name = mono_type_get_full_name (klass);
6519 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6520 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6521 mono_array_setref (msg->args, 2, arg);
6524 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6526 if (exc) mono_raise_exception ((MonoException *)exc);
6530 * mono_store_remote_field_new:
6536 * Missing documentation
6539 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6541 static MonoMethod *setter = NULL;
6542 MonoDomain *domain = mono_domain_get ();
6543 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6544 MonoClass *field_class;
6545 MonoMethodMessage *msg;
6546 MonoArray *out_args;
6550 g_assert (mono_object_is_transparent_proxy (this));
6552 field_class = mono_class_from_mono_type (field->type);
6554 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6555 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6556 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6561 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6565 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6566 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6568 full_name = mono_type_get_full_name (klass);
6569 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6570 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6571 mono_array_setref (msg->args, 2, arg);
6574 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6576 if (exc) mono_raise_exception ((MonoException *)exc);
6581 * mono_create_ftnptr:
6583 * Given a function address, create a function descriptor for it.
6584 * This is only needed on some platforms.
6587 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6589 return callbacks.create_ftnptr (domain, addr);
6593 * mono_get_addr_from_ftnptr:
6595 * Given a pointer to a function descriptor, return the function address.
6596 * This is only needed on some platforms.
6599 mono_get_addr_from_ftnptr (gpointer descr)
6601 return callbacks.get_addr_from_ftnptr (descr);
6605 * mono_string_chars:
6608 * Returns a pointer to the UCS16 characters stored in the MonoString
6611 mono_string_chars (MonoString *s)
6617 * mono_string_length:
6620 * Returns the lenght in characters of the string
6623 mono_string_length (MonoString *s)
6629 * mono_array_length:
6630 * @array: a MonoArray*
6632 * Returns the total number of elements in the array. This works for
6633 * both vectors and multidimensional arrays.
6636 mono_array_length (MonoArray *array)
6638 return array->max_length;
6642 * mono_array_addr_with_size:
6643 * @array: a MonoArray*
6644 * @size: size of the array elements
6645 * @idx: index into the array
6647 * Returns the address of the @idx element in the array.
6650 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6652 return ((char*)(array)->vector) + size * idx;