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 vt_slot = interface_offset;
1315 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1318 if (slot_num >= 0 && iface->is_inflated) {
1320 * The imt slot of the method is the same as for its declaring method,
1321 * see the comment in mono_method_get_imt_slot (), so we can
1322 * avoid inflating methods which will be discarded by
1323 * add_imt_builder_entry anyway.
1325 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1326 if (mono_method_get_imt_slot (method) != slot_num) {
1331 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1332 if (method->is_generic) {
1333 has_generic_virtual = TRUE;
1338 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1339 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1344 if (extra_interfaces) {
1345 int interface_offset = klass->vtable_size;
1347 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1348 MonoClass* iface = list_item->data;
1349 int method_slot_in_interface;
1350 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1351 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1352 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1354 interface_offset += iface->method.count;
1357 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1358 /* overwrite the imt slot only if we're building all the entries or if
1359 * we're building this specific one
1361 if (slot_num < 0 || i == slot_num) {
1362 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1365 if (imt_builder [i]) {
1366 MonoImtBuilderEntry *entry;
1368 /* Link entries with imt_builder [i] */
1369 for (entry = entries; entry->next; entry = entry->next) {
1371 MonoMethod *method = (MonoMethod*)entry->key;
1372 char *method_name = mono_method_full_name (method, TRUE);
1373 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1374 g_free (method_name);
1377 entry->next = imt_builder [i];
1378 entries->children += imt_builder [i]->children + 1;
1380 imt_builder [i] = entries;
1383 if (has_generic_virtual || has_variant_iface) {
1385 * There might be collisions later when the the thunk is expanded.
1387 imt_collisions_bitmap |= (1 << i);
1390 * The IMT thunk might be called with an instance of one of the
1391 * generic virtual methods, so has to fallback to the IMT trampoline.
1393 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1395 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1398 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1402 if (imt_builder [i] != NULL) {
1403 int methods_in_slot = imt_builder [i]->children + 1;
1404 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1405 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1406 record_method_count_for_max_collisions = TRUE;
1408 method_count += methods_in_slot;
1412 mono_stats.imt_number_of_methods += method_count;
1413 if (record_method_count_for_max_collisions) {
1414 mono_stats.imt_method_count_when_max_collisions = method_count;
1417 for (i = 0; i < MONO_IMT_SIZE; i++) {
1418 MonoImtBuilderEntry* entry = imt_builder [i];
1419 while (entry != NULL) {
1420 MonoImtBuilderEntry* next = entry->next;
1426 /* we OR the bitmap since we may build just a single imt slot at a time */
1427 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1431 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1432 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1436 * mono_vtable_build_imt_slot:
1437 * @vtable: virtual object table struct
1438 * @imt_slot: slot in the IMT table
1440 * Fill the given @imt_slot in the IMT table of @vtable with
1441 * a trampoline or a thunk for the case of collisions.
1442 * This is part of the internal mono API.
1444 * LOCKING: Take the domain lock.
1447 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1449 gpointer *imt = (gpointer*)vtable;
1450 imt -= MONO_IMT_SIZE;
1451 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1453 /* no support for extra interfaces: the proxy objects will need
1454 * to build the complete IMT
1455 * Update and heck needs to ahppen inside the proper domain lock, as all
1456 * the changes made to a MonoVTable.
1458 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1459 mono_domain_lock (vtable->domain);
1460 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1461 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1462 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1463 mono_domain_unlock (vtable->domain);
1464 mono_loader_unlock ();
1469 * The first two free list entries both belong to the wait list: The
1470 * first entry is the pointer to the head of the list and the second
1471 * entry points to the last element. That way appending and removing
1472 * the first element are both O(1) operations.
1474 #ifdef MONO_SMALL_CONFIG
1475 #define NUM_FREE_LISTS 6
1477 #define NUM_FREE_LISTS 12
1479 #define FIRST_FREE_LIST_SIZE 64
1480 #define MAX_WAIT_LENGTH 50
1481 #define THUNK_THRESHOLD 10
1484 * LOCKING: The domain lock must be held.
1487 init_thunk_free_lists (MonoDomain *domain)
1489 if (domain->thunk_free_lists)
1491 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1495 list_index_for_size (int item_size)
1498 int size = FIRST_FREE_LIST_SIZE;
1500 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1509 * mono_method_alloc_generic_virtual_thunk:
1511 * @size: size in bytes
1513 * Allocs size bytes to be used for the code of a generic virtual
1514 * thunk. It's either allocated from the domain's code manager or
1515 * reused from a previously invalidated piece.
1517 * LOCKING: The domain lock must be held.
1520 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1522 static gboolean inited = FALSE;
1523 static int generic_virtual_thunks_size = 0;
1527 MonoThunkFreeList **l;
1529 init_thunk_free_lists (domain);
1531 size += sizeof (guint32);
1532 if (size < sizeof (MonoThunkFreeList))
1533 size = sizeof (MonoThunkFreeList);
1535 i = list_index_for_size (size);
1536 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1537 if ((*l)->size >= size) {
1538 MonoThunkFreeList *item = *l;
1540 return ((guint32*)item) + 1;
1544 /* no suitable item found - search lists of larger sizes */
1545 while (++i < NUM_FREE_LISTS) {
1546 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1549 g_assert (item->size > size);
1550 domain->thunk_free_lists [i] = item->next;
1551 return ((guint32*)item) + 1;
1554 /* still nothing found - allocate it */
1556 mono_counters_register ("Generic virtual thunk bytes",
1557 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1560 generic_virtual_thunks_size += size;
1562 p = mono_domain_code_reserve (domain, size);
1565 mono_domain_lock (domain);
1566 if (!domain->generic_virtual_thunks)
1567 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1568 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1569 mono_domain_unlock (domain);
1575 * LOCKING: The domain lock must be held.
1578 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1581 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1582 gboolean found = FALSE;
1584 mono_domain_lock (domain);
1585 if (!domain->generic_virtual_thunks)
1586 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1587 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1589 mono_domain_unlock (domain);
1592 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1594 init_thunk_free_lists (domain);
1596 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1597 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1598 int length = item->length;
1601 /* unlink the first item from the wait list */
1602 domain->thunk_free_lists [0] = item->next;
1603 domain->thunk_free_lists [0]->length = length - 1;
1605 i = list_index_for_size (item->size);
1607 /* put it in the free list */
1608 item->next = domain->thunk_free_lists [i];
1609 domain->thunk_free_lists [i] = item;
1613 if (domain->thunk_free_lists [1]) {
1614 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1615 domain->thunk_free_lists [0]->length++;
1617 g_assert (!domain->thunk_free_lists [0]);
1619 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1620 domain->thunk_free_lists [0]->length = 1;
1624 typedef struct _GenericVirtualCase {
1628 struct _GenericVirtualCase *next;
1629 } GenericVirtualCase;
1632 * get_generic_virtual_entries:
1634 * Return IMT entries for the generic virtual method instances and
1635 * variant interface methods for vtable slot
1638 static MonoImtBuilderEntry*
1639 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1641 GenericVirtualCase *list;
1642 MonoImtBuilderEntry *entries;
1644 mono_domain_lock (domain);
1645 if (!domain->generic_virtual_cases)
1646 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1648 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1651 for (; list; list = list->next) {
1652 MonoImtBuilderEntry *entry;
1654 if (list->count < THUNK_THRESHOLD)
1657 entry = g_new0 (MonoImtBuilderEntry, 1);
1658 entry->key = list->method;
1659 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1660 entry->has_target_code = 1;
1662 entry->children = entries->children + 1;
1663 entry->next = entries;
1667 mono_domain_unlock (domain);
1669 /* FIXME: Leaking memory ? */
1674 * mono_method_add_generic_virtual_invocation:
1676 * @vtable_slot: pointer to the vtable slot
1677 * @method: the inflated generic virtual method
1678 * @code: the method's code
1680 * Registers a call via unmanaged code to a generic virtual method
1681 * instantiation or variant interface method. If the number of calls reaches a threshold
1682 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1683 * virtual method thunk.
1686 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1687 gpointer *vtable_slot,
1688 MonoMethod *method, gpointer code)
1690 static gboolean inited = FALSE;
1691 static int num_added = 0;
1693 GenericVirtualCase *gvc, *list;
1694 MonoImtBuilderEntry *entries;
1698 mono_domain_lock (domain);
1699 if (!domain->generic_virtual_cases)
1700 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1702 /* Check whether the case was already added */
1703 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1706 if (gvc->method == method)
1711 /* If not found, make a new one */
1713 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1714 gvc->method = method;
1717 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1719 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1722 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1728 if (++gvc->count == THUNK_THRESHOLD) {
1729 gpointer *old_thunk = *vtable_slot;
1730 gpointer vtable_trampoline = NULL;
1731 gpointer imt_trampoline = NULL;
1733 if ((gpointer)vtable_slot < (gpointer)vtable) {
1734 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1735 int imt_slot = MONO_IMT_SIZE + displacement;
1737 /* Force the rebuild of the thunk at the next call */
1738 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1739 *vtable_slot = imt_trampoline;
1741 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1743 entries = get_generic_virtual_entries (domain, vtable_slot);
1745 sorted = imt_sort_slot_entries (entries);
1747 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1751 MonoImtBuilderEntry *next = entries->next;
1756 for (i = 0; i < sorted->len; ++i)
1757 g_free (g_ptr_array_index (sorted, i));
1758 g_ptr_array_free (sorted, TRUE);
1761 #ifndef __native_client__
1762 /* We don't re-use any thunks as there is a lot of overhead */
1763 /* to deleting and re-using code in Native Client. */
1764 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1765 invalidate_generic_virtual_thunk (domain, old_thunk);
1769 mono_domain_unlock (domain);
1772 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1775 * mono_class_vtable:
1776 * @domain: the application domain
1777 * @class: the class to initialize
1779 * VTables are domain specific because we create domain specific code, and
1780 * they contain the domain specific static class data.
1781 * On failure, NULL is returned, and class->exception_type is set.
1784 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1786 return mono_class_vtable_full (domain, class, FALSE);
1790 * mono_class_vtable_full:
1791 * @domain: the application domain
1792 * @class: the class to initialize
1793 * @raise_on_error if an exception should be raised on failure or not
1795 * VTables are domain specific because we create domain specific code, and
1796 * they contain the domain specific static class data.
1799 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1801 MonoClassRuntimeInfo *runtime_info;
1805 if (class->exception_type) {
1807 mono_raise_exception (mono_class_get_exception_for_failure (class));
1811 /* this check can be inlined in jitted code, too */
1812 runtime_info = class->runtime_info;
1813 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1814 return runtime_info->domain_vtables [domain->domain_id];
1815 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1819 * mono_class_try_get_vtable:
1820 * @domain: the application domain
1821 * @class: the class to initialize
1823 * This function tries to get the associated vtable from @class if
1824 * it was already created.
1827 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1829 MonoClassRuntimeInfo *runtime_info;
1833 runtime_info = class->runtime_info;
1834 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1835 return runtime_info->domain_vtables [domain->domain_id];
1840 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1843 MonoClassRuntimeInfo *runtime_info, *old_info;
1844 MonoClassField *field;
1846 int i, vtable_slots;
1847 int imt_table_bytes = 0;
1849 guint32 vtable_size, class_size;
1852 gpointer *interface_offsets;
1854 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1855 mono_domain_lock (domain);
1856 runtime_info = class->runtime_info;
1857 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1858 mono_domain_unlock (domain);
1859 mono_loader_unlock ();
1860 return runtime_info->domain_vtables [domain->domain_id];
1862 if (!class->inited || class->exception_type) {
1863 if (!mono_class_init (class) || class->exception_type) {
1864 mono_domain_unlock (domain);
1865 mono_loader_unlock ();
1867 mono_raise_exception (mono_class_get_exception_for_failure (class));
1872 /* Array types require that their element type be valid*/
1873 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1874 MonoClass *element_class = class->element_class;
1875 if (!element_class->inited)
1876 mono_class_init (element_class);
1878 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1879 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1880 mono_class_setup_vtable (element_class);
1882 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1883 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1884 if (class->exception_type == MONO_EXCEPTION_NONE)
1885 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1886 mono_domain_unlock (domain);
1887 mono_loader_unlock ();
1889 mono_raise_exception (mono_class_get_exception_for_failure (class));
1895 * For some classes, mono_class_init () already computed class->vtable_size, and
1896 * that is all that is needed because of the vtable trampolines.
1898 if (!class->vtable_size)
1899 mono_class_setup_vtable (class);
1901 if (class->generic_class && !class->vtable)
1902 mono_class_check_vtable_constraints (class, NULL);
1904 /* Initialize klass->has_finalize */
1905 mono_class_has_finalizer (class);
1907 if (class->exception_type) {
1908 mono_domain_unlock (domain);
1909 mono_loader_unlock ();
1911 mono_raise_exception (mono_class_get_exception_for_failure (class));
1915 vtable_slots = class->vtable_size;
1916 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1917 class_size = mono_class_data_size (class);
1922 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1923 if (class->interface_offsets_count) {
1924 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1925 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1926 mono_stats.imt_number_of_tables++;
1927 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1930 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1931 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1934 mono_stats.used_class_count++;
1935 mono_stats.class_vtable_size += vtable_size;
1936 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1939 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1941 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1943 vt->rank = class->rank;
1944 vt->domain = domain;
1946 mono_class_compute_gc_descriptor (class);
1948 * We can't use typed allocation in the non-root domains, since the
1949 * collector needs the GC descriptor stored in the vtable even after
1950 * the mempool containing the vtable is destroyed when the domain is
1951 * unloaded. An alternative might be to allocate vtables in the GC
1952 * heap, but this does not seem to work (it leads to crashes inside
1953 * libgc). If that approach is tried, two gc descriptors need to be
1954 * allocated for each class: one for the root domain, and one for all
1955 * other domains. The second descriptor should contain a bit for the
1956 * vtable field in MonoObject, since we can no longer assume the
1957 * vtable is reachable by other roots after the appdomain is unloaded.
1959 #ifdef HAVE_BOEHM_GC
1960 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1961 vt->gc_descr = GC_NO_DESCRIPTOR;
1964 vt->gc_descr = class->gc_descr;
1966 gc_bits = mono_gc_get_vtable_bits (class);
1967 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1969 vt->gc_bits = gc_bits;
1972 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1973 if (class->has_static_refs) {
1974 gpointer statics_gc_descr;
1976 gsize default_bitmap [4] = {0};
1979 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1980 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1981 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1982 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1983 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1984 if (bitmap != default_bitmap)
1987 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1989 vt->has_static_fields = TRUE;
1990 mono_stats.class_static_data_size += class_size;
1995 while ((field = mono_class_get_fields (class, &iter))) {
1996 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1998 if (mono_field_is_deleted (field))
2000 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2001 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2002 if (special_static != SPECIAL_STATIC_NONE) {
2003 guint32 size, offset;
2005 gsize default_bitmap [4] = {0};
2010 if (mono_type_is_reference (field->type)) {
2011 default_bitmap [0] = 1;
2013 bitmap = default_bitmap;
2014 } else if (mono_type_is_struct (field->type)) {
2015 fclass = mono_class_from_mono_type (field->type);
2016 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2017 numbits = max_set + 1;
2019 default_bitmap [0] = 0;
2021 bitmap = default_bitmap;
2023 size = mono_type_size (field->type, &align);
2024 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2025 if (!domain->special_static_fields)
2026 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2027 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2028 if (bitmap != default_bitmap)
2031 * This marks the field as special static to speed up the
2032 * checks in mono_field_static_get/set_value ().
2038 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2039 MonoClass *fklass = mono_class_from_mono_type (field->type);
2040 const char *data = mono_field_get_data (field);
2042 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2043 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2044 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2047 if (fklass->valuetype) {
2048 memcpy (t, data, mono_class_value_size (fklass, NULL));
2050 /* it's a pointer type: add check */
2051 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2058 vt->max_interface_id = class->max_interface_id;
2059 vt->interface_bitmap = class->interface_bitmap;
2061 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2062 // class->name, class->interface_offsets_count);
2064 if (! ARCH_USE_IMT) {
2065 /* initialize interface offsets */
2066 for (i = 0; i < class->interface_offsets_count; ++i) {
2067 int interface_id = class->interfaces_packed [i]->interface_id;
2068 int slot = class->interface_offsets_packed [i];
2069 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2073 /* Initialize vtable */
2074 if (callbacks.get_vtable_trampoline) {
2075 // This also covers the AOT case
2076 for (i = 0; i < class->vtable_size; ++i) {
2077 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2080 mono_class_setup_vtable (class);
2082 for (i = 0; i < class->vtable_size; ++i) {
2085 if ((cm = class->vtable [i]))
2086 vt->vtable [i] = arch_create_jit_trampoline (cm);
2090 if (ARCH_USE_IMT && imt_table_bytes) {
2091 /* Now that the vtable is full, we can actually fill up the IMT */
2092 if (callbacks.get_imt_trampoline) {
2093 /* lazy construction of the IMT entries enabled */
2094 for (i = 0; i < MONO_IMT_SIZE; ++i)
2095 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2097 build_imt (class, vt, domain, interface_offsets, NULL);
2102 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2103 * re-acquire them and check if another thread has created the vtable in the meantime.
2105 /* Special case System.MonoType to avoid infinite recursion */
2106 if (class != mono_defaults.monotype_class) {
2107 /*FIXME check for OOM*/
2108 vt->type = mono_type_get_object (domain, &class->byval_arg);
2109 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2110 /* This is unregistered in
2111 unregister_vtable_reflection_type() in
2113 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2116 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2118 /* class_vtable_array keeps an array of created vtables
2120 g_ptr_array_add (domain->class_vtable_array, vt);
2121 /* class->runtime_info is protected by the loader lock, both when
2122 * it it enlarged and when it is stored info.
2126 * Store the vtable in class->runtime_info.
2127 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2129 mono_memory_barrier ();
2131 old_info = class->runtime_info;
2132 if (old_info && old_info->max_domain >= domain->domain_id) {
2133 /* someone already created a large enough runtime info */
2134 old_info->domain_vtables [domain->domain_id] = vt;
2136 int new_size = domain->domain_id;
2138 new_size = MAX (new_size, old_info->max_domain);
2140 /* make the new size a power of two */
2142 while (new_size > i)
2145 /* this is a bounded memory retention issue: may want to
2146 * handle it differently when we'll have a rcu-like system.
2148 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2149 runtime_info->max_domain = new_size - 1;
2150 /* copy the stuff from the older info */
2152 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2154 runtime_info->domain_vtables [domain->domain_id] = vt;
2156 mono_memory_barrier ();
2157 class->runtime_info = runtime_info;
2160 if (class == mono_defaults.monotype_class) {
2161 /*FIXME check for OOM*/
2162 vt->type = mono_type_get_object (domain, &class->byval_arg);
2163 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2164 /* This is unregistered in
2165 unregister_vtable_reflection_type() in
2167 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2170 mono_domain_unlock (domain);
2171 mono_loader_unlock ();
2173 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2174 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2175 mono_raise_exception (mono_class_get_exception_for_failure (class));
2177 /* make sure the parent is initialized */
2178 /*FIXME shouldn't this fail the current type?*/
2180 mono_class_vtable_full (domain, class->parent, raise_on_error);
2185 #ifndef DISABLE_REMOTING
2187 * mono_class_proxy_vtable:
2188 * @domain: the application domain
2189 * @remove_class: the remote class
2191 * Creates a vtable for transparent proxies. It is basically
2192 * a copy of the real vtable of the class wrapped in @remote_class,
2193 * but all function pointers invoke the remoting functions, and
2194 * vtable->klass points to the transparent proxy class, and not to @class.
2197 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2200 MonoVTable *vt, *pvt;
2201 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2203 GSList *extra_interfaces = NULL;
2204 MonoClass *class = remote_class->proxy_class;
2205 gpointer *interface_offsets;
2209 #ifdef COMPRESSED_INTERFACE_BITMAP
2213 vt = mono_class_vtable (domain, class);
2214 g_assert (vt); /*FIXME property handle failure*/
2215 max_interface_id = vt->max_interface_id;
2217 /* Calculate vtable space for extra interfaces */
2218 for (j = 0; j < remote_class->interface_count; j++) {
2219 MonoClass* iclass = remote_class->interfaces[j];
2223 /*FIXME test for interfaces with variant generic arguments*/
2224 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2225 continue; /* interface implemented by the class */
2226 if (g_slist_find (extra_interfaces, iclass))
2229 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2231 method_count = mono_class_num_methods (iclass);
2233 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2234 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2236 for (i = 0; i < ifaces->len; ++i) {
2237 MonoClass *ic = g_ptr_array_index (ifaces, i);
2238 /*FIXME test for interfaces with variant generic arguments*/
2239 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2240 continue; /* interface implemented by the class */
2241 if (g_slist_find (extra_interfaces, ic))
2243 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2244 method_count += mono_class_num_methods (ic);
2246 g_ptr_array_free (ifaces, TRUE);
2249 extra_interface_vtsize += method_count * sizeof (gpointer);
2250 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2254 mono_stats.imt_number_of_tables++;
2255 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2256 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2257 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2259 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2260 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2263 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2265 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2267 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2269 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2270 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2272 pvt->klass = mono_defaults.transparent_proxy_class;
2273 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2274 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2276 /* initialize vtable */
2277 mono_class_setup_vtable (class);
2278 for (i = 0; i < class->vtable_size; ++i) {
2281 if ((cm = class->vtable [i]))
2282 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2284 pvt->vtable [i] = NULL;
2287 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2288 /* create trampolines for abstract methods */
2289 for (k = class; k; k = k->parent) {
2291 gpointer iter = NULL;
2292 while ((m = mono_class_get_methods (k, &iter)))
2293 if (!pvt->vtable [m->slot])
2294 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2298 pvt->max_interface_id = max_interface_id;
2299 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2300 #ifdef COMPRESSED_INTERFACE_BITMAP
2301 bitmap = g_malloc0 (bsize);
2303 bitmap = mono_domain_alloc0 (domain, bsize);
2306 if (! ARCH_USE_IMT) {
2307 /* initialize interface offsets */
2308 for (i = 0; i < class->interface_offsets_count; ++i) {
2309 int interface_id = class->interfaces_packed [i]->interface_id;
2310 int slot = class->interface_offsets_packed [i];
2311 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2314 for (i = 0; i < class->interface_offsets_count; ++i) {
2315 int interface_id = class->interfaces_packed [i]->interface_id;
2316 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2319 if (extra_interfaces) {
2320 int slot = class->vtable_size;
2326 /* Create trampolines for the methods of the interfaces */
2327 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2328 interf = list_item->data;
2330 if (! ARCH_USE_IMT) {
2331 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2333 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2337 while ((cm = mono_class_get_methods (interf, &iter)))
2338 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2340 slot += mono_class_num_methods (interf);
2342 if (! ARCH_USE_IMT) {
2343 g_slist_free (extra_interfaces);
2348 /* Now that the vtable is full, we can actually fill up the IMT */
2349 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2350 if (extra_interfaces) {
2351 g_slist_free (extra_interfaces);
2355 #ifdef COMPRESSED_INTERFACE_BITMAP
2356 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2357 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2358 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2361 pvt->interface_bitmap = bitmap;
2366 #endif /* DISABLE_REMOTING */
2369 * mono_class_field_is_special_static:
2371 * Returns whether @field is a thread/context static field.
2374 mono_class_field_is_special_static (MonoClassField *field)
2376 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2378 if (mono_field_is_deleted (field))
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2381 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2388 * mono_class_field_get_special_static_type:
2389 * @field: The MonoClassField describing the field.
2391 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2392 * SPECIAL_STATIC_NONE otherwise.
2395 mono_class_field_get_special_static_type (MonoClassField *field)
2397 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2398 return SPECIAL_STATIC_NONE;
2399 if (mono_field_is_deleted (field))
2400 return SPECIAL_STATIC_NONE;
2401 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2402 return field_is_special_static (field->parent, field);
2403 return SPECIAL_STATIC_NONE;
2407 * mono_class_has_special_static_fields:
2409 * Returns whenever @klass has any thread/context static fields.
2412 mono_class_has_special_static_fields (MonoClass *klass)
2414 MonoClassField *field;
2418 while ((field = mono_class_get_fields (klass, &iter))) {
2419 g_assert (field->parent == klass);
2420 if (mono_class_field_is_special_static (field))
2427 #ifndef DISABLE_REMOTING
2429 * create_remote_class_key:
2430 * Creates an array of pointers that can be used as a hash key for a remote class.
2431 * The first element of the array is the number of pointers.
2434 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2439 if (remote_class == NULL) {
2440 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2441 key = g_malloc (sizeof(gpointer) * 3);
2442 key [0] = GINT_TO_POINTER (2);
2443 key [1] = mono_defaults.marshalbyrefobject_class;
2444 key [2] = extra_class;
2446 key = g_malloc (sizeof(gpointer) * 2);
2447 key [0] = GINT_TO_POINTER (1);
2448 key [1] = extra_class;
2451 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2452 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2453 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2454 key [1] = remote_class->proxy_class;
2456 // Keep the list of interfaces sorted
2457 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2458 if (extra_class && remote_class->interfaces [i] > extra_class) {
2459 key [j++] = extra_class;
2462 key [j] = remote_class->interfaces [i];
2465 key [j] = extra_class;
2467 // Replace the old class. The interface list is the same
2468 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2469 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2470 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2471 for (i = 0; i < remote_class->interface_count; i++)
2472 key [2 + i] = remote_class->interfaces [i];
2480 * copy_remote_class_key:
2482 * Make a copy of KEY in the domain and return the copy.
2485 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2487 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2488 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2490 memcpy (mp_key, key, key_size);
2496 * mono_remote_class:
2497 * @domain: the application domain
2498 * @class_name: name of the remote class
2500 * Creates and initializes a MonoRemoteClass object for a remote type.
2502 * Can raise an exception on failure.
2505 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2508 MonoRemoteClass *rc;
2509 gpointer* key, *mp_key;
2512 key = create_remote_class_key (NULL, proxy_class);
2514 mono_domain_lock (domain);
2515 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2519 mono_domain_unlock (domain);
2523 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2524 if (!mono_error_ok (&error)) {
2526 mono_domain_unlock (domain);
2527 mono_error_raise_exception (&error);
2530 mp_key = copy_remote_class_key (domain, key);
2534 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2535 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2536 rc->interface_count = 1;
2537 rc->interfaces [0] = proxy_class;
2538 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2540 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2541 rc->interface_count = 0;
2542 rc->proxy_class = proxy_class;
2545 rc->default_vtable = NULL;
2546 rc->xdomain_vtable = NULL;
2547 rc->proxy_class_name = name;
2548 #ifndef DISABLE_PERFCOUNTERS
2549 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2552 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2554 mono_domain_unlock (domain);
2559 * clone_remote_class:
2560 * Creates a copy of the remote_class, adding the provided class or interface
2562 static MonoRemoteClass*
2563 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2565 MonoRemoteClass *rc;
2566 gpointer* key, *mp_key;
2568 key = create_remote_class_key (remote_class, extra_class);
2569 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2575 mp_key = copy_remote_class_key (domain, key);
2579 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2581 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2582 rc->proxy_class = remote_class->proxy_class;
2583 rc->interface_count = remote_class->interface_count + 1;
2585 // Keep the list of interfaces sorted, since the hash key of
2586 // the remote class depends on this
2587 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2588 if (remote_class->interfaces [i] > extra_class && i == j)
2589 rc->interfaces [j++] = extra_class;
2590 rc->interfaces [j] = remote_class->interfaces [i];
2593 rc->interfaces [j] = extra_class;
2595 // Replace the old class. The interface array is the same
2596 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2597 rc->proxy_class = extra_class;
2598 rc->interface_count = remote_class->interface_count;
2599 if (rc->interface_count > 0)
2600 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2603 rc->default_vtable = NULL;
2604 rc->xdomain_vtable = NULL;
2605 rc->proxy_class_name = remote_class->proxy_class_name;
2607 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2613 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2615 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2616 mono_domain_lock (domain);
2617 if (rp->target_domain_id != -1) {
2618 if (remote_class->xdomain_vtable == NULL)
2619 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2620 mono_domain_unlock (domain);
2621 mono_loader_unlock ();
2622 return remote_class->xdomain_vtable;
2624 if (remote_class->default_vtable == NULL) {
2627 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2628 klass = mono_class_from_mono_type (type);
2630 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)))
2631 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2634 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2637 mono_domain_unlock (domain);
2638 mono_loader_unlock ();
2639 return remote_class->default_vtable;
2643 * mono_upgrade_remote_class:
2644 * @domain: the application domain
2645 * @tproxy: the proxy whose remote class has to be upgraded.
2646 * @klass: class to which the remote class can be casted.
2648 * Updates the vtable of the remote class by adding the necessary method slots
2649 * and interface offsets so it can be safely casted to klass. klass can be a
2650 * class or an interface.
2653 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2655 MonoTransparentProxy *tproxy;
2656 MonoRemoteClass *remote_class;
2657 gboolean redo_vtable;
2659 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2660 mono_domain_lock (domain);
2662 tproxy = (MonoTransparentProxy*) proxy_object;
2663 remote_class = tproxy->remote_class;
2665 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2668 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2669 if (remote_class->interfaces [i] == klass)
2670 redo_vtable = FALSE;
2673 redo_vtable = (remote_class->proxy_class != klass);
2677 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2678 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2681 mono_domain_unlock (domain);
2682 mono_loader_unlock ();
2684 #endif /* DISABLE_REMOTING */
2688 * mono_object_get_virtual_method:
2689 * @obj: object to operate on.
2692 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2693 * the instance of a callvirt of method.
2696 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2699 MonoMethod **vtable;
2700 gboolean is_proxy = FALSE;
2701 MonoMethod *res = NULL;
2703 klass = mono_object_class (obj);
2704 #ifndef DISABLE_REMOTING
2705 if (klass == mono_defaults.transparent_proxy_class) {
2706 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2711 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2714 mono_class_setup_vtable (klass);
2715 vtable = klass->vtable;
2717 if (method->slot == -1) {
2718 /* method->slot might not be set for instances of generic methods */
2719 if (method->is_inflated) {
2720 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2721 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2724 g_assert_not_reached ();
2728 /* check method->slot is a valid index: perform isinstance? */
2729 if (method->slot != -1) {
2730 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2732 gboolean variance_used = FALSE;
2733 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2734 g_assert (iface_offset > 0);
2735 res = vtable [iface_offset + method->slot];
2738 res = vtable [method->slot];
2742 #ifndef DISABLE_REMOTING
2744 /* It may be an interface, abstract class method or generic method */
2745 if (!res || mono_method_signature (res)->generic_param_count)
2748 /* generic methods demand invoke_with_check */
2749 if (mono_method_signature (res)->generic_param_count)
2750 res = mono_marshal_get_remoting_invoke_with_check (res);
2753 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2754 res = mono_cominterop_get_invoke (res);
2757 res = mono_marshal_get_remoting_invoke (res);
2762 if (method->is_inflated) {
2763 /* Have to inflate the result */
2764 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2774 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2776 g_error ("runtime invoke called on uninitialized runtime");
2780 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2783 * mono_runtime_invoke:
2784 * @method: method to invoke
2785 * @obJ: object instance
2786 * @params: arguments to the method
2787 * @exc: exception information.
2789 * Invokes the method represented by @method on the object @obj.
2791 * obj is the 'this' pointer, it should be NULL for static
2792 * methods, a MonoObject* for object instances and a pointer to
2793 * the value type for value types.
2795 * The params array contains the arguments to the method with the
2796 * same convention: MonoObject* pointers for object instances and
2797 * pointers to the value type otherwise.
2799 * From unmanaged code you'll usually use the
2800 * mono_runtime_invoke() variant.
2802 * Note that this function doesn't handle virtual methods for
2803 * you, it will exec the exact method you pass: we still need to
2804 * expose a function to lookup the derived class implementation
2805 * of a virtual method (there are examples of this in the code,
2808 * You can pass NULL as the exc argument if you don't want to
2809 * catch exceptions, otherwise, *exc will be set to the exception
2810 * thrown, if any. if an exception is thrown, you can't use the
2811 * MonoObject* result from the function.
2813 * If the method returns a value type, it is boxed in an object
2817 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2821 if (mono_runtime_get_no_exec ())
2822 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2824 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2825 mono_profiler_method_start_invoke (method);
2827 result = default_mono_runtime_invoke (method, obj, params, exc);
2829 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2830 mono_profiler_method_end_invoke (method);
2836 * mono_method_get_unmanaged_thunk:
2837 * @method: method to generate a thunk for.
2839 * Returns an unmanaged->managed thunk that can be used to call
2840 * a managed method directly from C.
2842 * The thunk's C signature closely matches the managed signature:
2844 * C#: public bool Equals (object obj);
2845 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2846 * MonoObject*, MonoException**);
2848 * The 1st ("this") parameter must not be used with static methods:
2850 * C#: public static bool ReferenceEquals (object a, object b);
2851 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2854 * The last argument must be a non-null pointer of a MonoException* pointer.
2855 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2856 * exception has been thrown in managed code. Otherwise it will point
2857 * to the MonoException* caught by the thunk. In this case, the result of
2858 * the thunk is undefined:
2860 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2861 * MonoException *ex = NULL;
2862 * Equals func = mono_method_get_unmanaged_thunk (method);
2863 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2865 * // handle exception
2868 * The calling convention of the thunk matches the platform's default
2869 * convention. This means that under Windows, C declarations must
2870 * contain the __stdcall attribute:
2872 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2873 * MonoObject*, MonoException**);
2877 * Value type arguments and return values are treated as they were objects:
2879 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2880 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2882 * Arguments must be properly boxed upon trunk's invocation, while return
2883 * values must be unboxed.
2886 mono_method_get_unmanaged_thunk (MonoMethod *method)
2888 method = mono_marshal_get_thunk_invoke_wrapper (method);
2889 return mono_compile_method (method);
2893 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2897 /* object fields cannot be byref, so we don't need a
2899 gpointer *p = (gpointer*)dest;
2906 case MONO_TYPE_BOOLEAN:
2908 case MONO_TYPE_U1: {
2909 guint8 *p = (guint8*)dest;
2910 *p = value ? *(guint8*)value : 0;
2915 case MONO_TYPE_CHAR: {
2916 guint16 *p = (guint16*)dest;
2917 *p = value ? *(guint16*)value : 0;
2920 #if SIZEOF_VOID_P == 4
2925 case MONO_TYPE_U4: {
2926 gint32 *p = (gint32*)dest;
2927 *p = value ? *(gint32*)value : 0;
2930 #if SIZEOF_VOID_P == 8
2935 case MONO_TYPE_U8: {
2936 gint64 *p = (gint64*)dest;
2937 *p = value ? *(gint64*)value : 0;
2940 case MONO_TYPE_R4: {
2941 float *p = (float*)dest;
2942 *p = value ? *(float*)value : 0;
2945 case MONO_TYPE_R8: {
2946 double *p = (double*)dest;
2947 *p = value ? *(double*)value : 0;
2950 case MONO_TYPE_STRING:
2951 case MONO_TYPE_SZARRAY:
2952 case MONO_TYPE_CLASS:
2953 case MONO_TYPE_OBJECT:
2954 case MONO_TYPE_ARRAY:
2955 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2957 case MONO_TYPE_FNPTR:
2958 case MONO_TYPE_PTR: {
2959 gpointer *p = (gpointer*)dest;
2960 *p = deref_pointer? *(gpointer*)value: value;
2963 case MONO_TYPE_VALUETYPE:
2964 /* note that 't' and 'type->type' can be different */
2965 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2966 t = mono_class_enum_basetype (type->data.klass)->type;
2969 MonoClass *class = mono_class_from_mono_type (type);
2970 int size = mono_class_value_size (class, NULL);
2972 mono_gc_bzero (dest, size);
2974 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2977 case MONO_TYPE_GENERICINST:
2978 t = type->data.generic_class->container_class->byval_arg.type;
2981 g_error ("got type %x", type->type);
2986 * mono_field_set_value:
2987 * @obj: Instance object
2988 * @field: MonoClassField describing the field to set
2989 * @value: The value to be set
2991 * Sets the value of the field described by @field in the object instance @obj
2992 * to the value passed in @value. This method should only be used for instance
2993 * fields. For static fields, use mono_field_static_set_value.
2995 * The value must be on the native format of the field type.
2998 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3002 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3004 dest = (char*)obj + field->offset;
3005 set_value (field->type, dest, value, FALSE);
3009 * mono_field_static_set_value:
3010 * @field: MonoClassField describing the field to set
3011 * @value: The value to be set
3013 * Sets the value of the static field described by @field
3014 * to the value passed in @value.
3016 * The value must be on the native format of the field type.
3019 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3023 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3024 /* you cant set a constant! */
3025 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3027 if (field->offset == -1) {
3028 /* Special static */
3031 mono_domain_lock (vt->domain);
3032 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3033 mono_domain_unlock (vt->domain);
3034 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3036 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3038 set_value (field->type, dest, value, FALSE);
3042 * mono_vtable_get_static_field_data:
3044 * Internal use function: return a pointer to the memory holding the static fields
3045 * for a class or NULL if there are no static fields.
3046 * This is exported only for use by the debugger.
3049 mono_vtable_get_static_field_data (MonoVTable *vt)
3051 if (!vt->has_static_fields)
3053 return vt->vtable [vt->klass->vtable_size];
3057 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3061 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3062 if (field->offset == -1) {
3063 /* Special static */
3066 mono_domain_lock (vt->domain);
3067 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3068 mono_domain_unlock (vt->domain);
3069 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3071 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3074 src = (guint8*)obj + field->offset;
3081 * mono_field_get_value:
3082 * @obj: Object instance
3083 * @field: MonoClassField describing the field to fetch information from
3084 * @value: pointer to the location where the value will be stored
3086 * Use this routine to get the value of the field @field in the object
3089 * The pointer provided by value must be of the field type, for reference
3090 * types this is a MonoObject*, for value types its the actual pointer to
3095 * mono_field_get_value (obj, int_field, &i);
3098 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3104 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3106 src = (char*)obj + field->offset;
3107 set_value (field->type, value, src, TRUE);
3111 * mono_field_get_value_object:
3112 * @domain: domain where the object will be created (if boxing)
3113 * @field: MonoClassField describing the field to fetch information from
3114 * @obj: The object instance for the field.
3116 * Returns: a new MonoObject with the value from the given field. If the
3117 * field represents a value type, the value is boxed.
3121 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3125 MonoVTable *vtable = NULL;
3127 gboolean is_static = FALSE;
3128 gboolean is_ref = FALSE;
3129 gboolean is_literal = FALSE;
3130 gboolean is_ptr = FALSE;
3132 MonoType *type = mono_field_get_type_checked (field, &error);
3134 if (!mono_error_ok (&error))
3135 mono_error_raise_exception (&error);
3137 switch (type->type) {
3138 case MONO_TYPE_STRING:
3139 case MONO_TYPE_OBJECT:
3140 case MONO_TYPE_CLASS:
3141 case MONO_TYPE_ARRAY:
3142 case MONO_TYPE_SZARRAY:
3147 case MONO_TYPE_BOOLEAN:
3150 case MONO_TYPE_CHAR:
3159 case MONO_TYPE_VALUETYPE:
3160 is_ref = type->byref;
3162 case MONO_TYPE_GENERICINST:
3163 is_ref = !mono_type_generic_inst_is_valuetype (type);
3169 g_error ("type 0x%x not handled in "
3170 "mono_field_get_value_object", type->type);
3174 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3177 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3181 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3182 if (!vtable->initialized)
3183 mono_runtime_class_init (vtable);
3191 get_default_field_value (domain, field, &o);
3192 } else if (is_static) {
3193 mono_field_static_get_value (vtable, field, &o);
3195 mono_field_get_value (obj, field, &o);
3201 static MonoMethod *m;
3207 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3208 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3214 get_default_field_value (domain, field, v);
3215 } else if (is_static) {
3216 mono_field_static_get_value (vtable, field, v);
3218 mono_field_get_value (obj, field, v);
3221 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3223 args [1] = mono_type_get_object (mono_domain_get (), type);
3225 return mono_runtime_invoke (m, NULL, args, NULL);
3228 /* boxed value type */
3229 klass = mono_class_from_mono_type (type);
3231 if (mono_class_is_nullable (klass))
3232 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3234 o = mono_object_new (domain, klass);
3235 v = ((gchar *) o) + sizeof (MonoObject);
3238 get_default_field_value (domain, field, v);
3239 } else if (is_static) {
3240 mono_field_static_get_value (vtable, field, v);
3242 mono_field_get_value (obj, field, v);
3249 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3252 const char *p = blob;
3253 mono_metadata_decode_blob_size (p, &p);
3256 case MONO_TYPE_BOOLEAN:
3259 *(guint8 *) value = *p;
3261 case MONO_TYPE_CHAR:
3264 *(guint16*) value = read16 (p);
3268 *(guint32*) value = read32 (p);
3272 *(guint64*) value = read64 (p);
3275 readr4 (p, (float*) value);
3278 readr8 (p, (double*) value);
3280 case MONO_TYPE_STRING:
3281 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3283 case MONO_TYPE_CLASS:
3284 *(gpointer*) value = NULL;
3288 g_warning ("type 0x%02x should not be in constant table", type);
3294 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3296 MonoTypeEnum def_type;
3299 data = mono_class_get_field_default_value (field, &def_type);
3300 mono_get_constant_value_from_blob (domain, def_type, data, value);
3304 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3308 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3310 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3311 get_default_field_value (vt->domain, field, value);
3315 if (field->offset == -1) {
3316 /* Special static */
3317 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3318 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3320 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3322 set_value (field->type, value, src, TRUE);
3326 * mono_field_static_get_value:
3327 * @vt: vtable to the object
3328 * @field: MonoClassField describing the field to fetch information from
3329 * @value: where the value is returned
3331 * Use this routine to get the value of the static field @field value.
3333 * The pointer provided by value must be of the field type, for reference
3334 * types this is a MonoObject*, for value types its the actual pointer to
3339 * mono_field_static_get_value (vt, int_field, &i);
3342 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3344 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3348 * mono_property_set_value:
3349 * @prop: MonoProperty to set
3350 * @obj: instance object on which to act
3351 * @params: parameters to pass to the propery
3352 * @exc: optional exception
3354 * Invokes the property's set method with the given arguments on the
3355 * object instance obj (or NULL for static properties).
3357 * You can pass NULL as the exc argument if you don't want to
3358 * catch exceptions, otherwise, *exc will be set to the exception
3359 * thrown, if any. if an exception is thrown, you can't use the
3360 * MonoObject* result from the function.
3363 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3365 default_mono_runtime_invoke (prop->set, obj, params, exc);
3369 * mono_property_get_value:
3370 * @prop: MonoProperty to fetch
3371 * @obj: instance object on which to act
3372 * @params: parameters to pass to the propery
3373 * @exc: optional exception
3375 * Invokes the property's get method with the given arguments on the
3376 * object instance obj (or NULL for static properties).
3378 * You can pass NULL as the exc argument if you don't want to
3379 * catch exceptions, otherwise, *exc will be set to the exception
3380 * thrown, if any. if an exception is thrown, you can't use the
3381 * MonoObject* result from the function.
3383 * Returns: the value from invoking the get method on the property.
3386 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3388 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3392 * mono_nullable_init:
3393 * @buf: The nullable structure to initialize.
3394 * @value: the value to initialize from
3395 * @klass: the type for the object
3397 * Initialize the nullable structure pointed to by @buf from @value which
3398 * should be a boxed value type. The size of @buf should be able to hold
3399 * as much data as the @klass->instance_size (which is the number of bytes
3400 * that will be copies).
3402 * Since Nullables have variable structure, we can not define a C
3403 * structure for them.
3406 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3408 MonoClass *param_class = klass->cast_class;
3410 mono_class_setup_fields_locking (klass);
3411 g_assert (klass->fields_inited);
3413 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3414 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3416 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3418 if (param_class->has_references)
3419 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3421 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3423 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3428 * mono_nullable_box:
3429 * @buf: The buffer representing the data to be boxed
3430 * @klass: the type to box it as.
3432 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3436 mono_nullable_box (guint8 *buf, MonoClass *klass)
3438 MonoClass *param_class = klass->cast_class;
3440 mono_class_setup_fields_locking (klass);
3441 g_assert (klass->fields_inited);
3443 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3444 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3446 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3447 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3448 if (param_class->has_references)
3449 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3451 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3459 * mono_get_delegate_invoke:
3460 * @klass: The delegate class
3462 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3465 mono_get_delegate_invoke (MonoClass *klass)
3469 /* This is called at runtime, so avoid the slower search in metadata */
3470 mono_class_setup_methods (klass);
3471 if (klass->exception_type)
3473 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3478 * mono_get_delegate_begin_invoke:
3479 * @klass: The delegate class
3481 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3484 mono_get_delegate_begin_invoke (MonoClass *klass)
3488 /* This is called at runtime, so avoid the slower search in metadata */
3489 mono_class_setup_methods (klass);
3490 if (klass->exception_type)
3492 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3497 * mono_get_delegate_end_invoke:
3498 * @klass: The delegate class
3500 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3503 mono_get_delegate_end_invoke (MonoClass *klass)
3507 /* This is called at runtime, so avoid the slower search in metadata */
3508 mono_class_setup_methods (klass);
3509 if (klass->exception_type)
3511 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3516 * mono_runtime_delegate_invoke:
3517 * @delegate: pointer to a delegate object.
3518 * @params: parameters for the delegate.
3519 * @exc: Pointer to the exception result.
3521 * Invokes the delegate method @delegate with the parameters provided.
3523 * You can pass NULL as the exc argument if you don't want to
3524 * catch exceptions, otherwise, *exc will be set to the exception
3525 * thrown, if any. if an exception is thrown, you can't use the
3526 * MonoObject* result from the function.
3529 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3532 MonoClass *klass = delegate->vtable->klass;
3534 im = mono_get_delegate_invoke (klass);
3536 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3538 return mono_runtime_invoke (im, delegate, params, exc);
3541 static char **main_args = NULL;
3542 static int num_main_args;
3545 * mono_runtime_get_main_args:
3547 * Returns: a MonoArray with the arguments passed to the main program
3550 mono_runtime_get_main_args (void)
3554 MonoDomain *domain = mono_domain_get ();
3559 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3561 for (i = 0; i < num_main_args; ++i)
3562 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3568 free_main_args (void)
3572 for (i = 0; i < num_main_args; ++i)
3573 g_free (main_args [i]);
3578 * mono_runtime_run_main:
3579 * @method: the method to start the application with (usually Main)
3580 * @argc: number of arguments from the command line
3581 * @argv: array of strings from the command line
3582 * @exc: excetption results
3584 * Execute a standard Main() method (argc/argv contains the
3585 * executable name). This method also sets the command line argument value
3586 * needed by System.Environment.
3591 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3595 MonoArray *args = NULL;
3596 MonoDomain *domain = mono_domain_get ();
3597 gchar *utf8_fullpath;
3598 MonoMethodSignature *sig;
3600 g_assert (method != NULL);
3602 mono_thread_set_main (mono_thread_current ());
3604 main_args = g_new0 (char*, argc);
3605 num_main_args = argc;
3607 if (!g_path_is_absolute (argv [0])) {
3608 gchar *basename = g_path_get_basename (argv [0]);
3609 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3613 utf8_fullpath = mono_utf8_from_external (fullpath);
3614 if(utf8_fullpath == NULL) {
3615 /* Printing the arg text will cause glib to
3616 * whinge about "Invalid UTF-8", but at least
3617 * its relevant, and shows the problem text
3620 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3621 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3628 utf8_fullpath = mono_utf8_from_external (argv[0]);
3629 if(utf8_fullpath == NULL) {
3630 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3631 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3636 main_args [0] = utf8_fullpath;
3638 for (i = 1; i < argc; ++i) {
3641 utf8_arg=mono_utf8_from_external (argv[i]);
3642 if(utf8_arg==NULL) {
3643 /* Ditto the comment about Invalid UTF-8 here */
3644 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3645 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3649 main_args [i] = utf8_arg;
3654 sig = mono_method_signature (method);
3656 g_print ("Unable to load Main method.\n");
3660 if (sig->param_count) {
3661 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3662 for (i = 0; i < argc; ++i) {
3663 /* The encodings should all work, given that
3664 * we've checked all these args for the
3667 gchar *str = mono_utf8_from_external (argv [i]);
3668 MonoString *arg = mono_string_new (domain, str);
3669 mono_array_setref (args, i, arg);
3673 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3676 mono_assembly_set_main (method->klass->image->assembly);
3678 return mono_runtime_exec_main (method, args, exc);
3682 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3684 static MonoMethod *serialize_method;
3689 if (!serialize_method) {
3690 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3691 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3694 if (!serialize_method) {
3699 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3703 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3711 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3713 static MonoMethod *deserialize_method;
3718 if (!deserialize_method) {
3719 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3720 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3722 if (!deserialize_method) {
3729 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3736 #ifndef DISABLE_REMOTING
3738 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3740 static MonoMethod *get_proxy_method;
3742 MonoDomain *domain = mono_domain_get ();
3743 MonoRealProxy *real_proxy;
3744 MonoReflectionType *reflection_type;
3745 MonoTransparentProxy *transparent_proxy;
3747 if (!get_proxy_method)
3748 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3750 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3752 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3753 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3755 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3756 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3759 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3763 return (MonoObject*) transparent_proxy;
3765 #endif /* DISABLE_REMOTING */
3768 * mono_object_xdomain_representation
3770 * @target_domain: a domain
3771 * @exc: pointer to a MonoObject*
3773 * Creates a representation of obj in the domain target_domain. This
3774 * is either a copy of obj arrived through via serialization and
3775 * deserialization or a proxy, depending on whether the object is
3776 * serializable or marshal by ref. obj must not be in target_domain.
3778 * If the object cannot be represented in target_domain, NULL is
3779 * returned and *exc is set to an appropriate exception.
3782 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3784 MonoObject *deserialized = NULL;
3785 gboolean failure = FALSE;
3789 #ifndef DISABLE_REMOTING
3790 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3791 deserialized = make_transparent_proxy (obj, &failure, exc);
3796 MonoDomain *domain = mono_domain_get ();
3797 MonoObject *serialized;
3799 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3800 serialized = serialize_object (obj, &failure, exc);
3801 mono_domain_set_internal_with_options (target_domain, FALSE);
3803 deserialized = deserialize_object (serialized, &failure, exc);
3804 if (domain != target_domain)
3805 mono_domain_set_internal_with_options (domain, FALSE);
3808 return deserialized;
3811 /* Used in call_unhandled_exception_delegate */
3813 create_unhandled_exception_eventargs (MonoObject *exc)
3817 MonoMethod *method = NULL;
3818 MonoBoolean is_terminating = TRUE;
3821 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3824 mono_class_init (klass);
3826 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3827 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3831 args [1] = &is_terminating;
3833 obj = mono_object_new (mono_domain_get (), klass);
3834 mono_runtime_invoke (method, obj, args, NULL);
3839 /* Used in mono_unhandled_exception */
3841 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3842 MonoObject *e = NULL;
3844 MonoDomain *current_domain = mono_domain_get ();
3846 if (domain != current_domain)
3847 mono_domain_set_internal_with_options (domain, FALSE);
3849 g_assert (domain == mono_object_domain (domain->domain));
3851 if (mono_object_domain (exc) != domain) {
3852 MonoObject *serialization_exc;
3854 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3856 if (serialization_exc) {
3858 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3861 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3862 "System.Runtime.Serialization", "SerializationException",
3863 "Could not serialize unhandled exception.");
3867 g_assert (mono_object_domain (exc) == domain);
3869 pa [0] = domain->domain;
3870 pa [1] = create_unhandled_exception_eventargs (exc);
3871 mono_runtime_delegate_invoke (delegate, pa, &e);
3873 if (domain != current_domain)
3874 mono_domain_set_internal_with_options (current_domain, FALSE);
3878 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3879 if (!mono_error_ok (&error)) {
3880 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3881 mono_error_cleanup (&error);
3883 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3889 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3892 * mono_runtime_unhandled_exception_policy_set:
3893 * @policy: the new policy
3895 * This is a VM internal routine.
3897 * Sets the runtime policy for handling unhandled exceptions.
3900 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3901 runtime_unhandled_exception_policy = policy;
3905 * mono_runtime_unhandled_exception_policy_get:
3907 * This is a VM internal routine.
3909 * Gets the runtime policy for handling unhandled exceptions.
3911 MonoRuntimeUnhandledExceptionPolicy
3912 mono_runtime_unhandled_exception_policy_get (void) {
3913 return runtime_unhandled_exception_policy;
3917 * mono_unhandled_exception:
3918 * @exc: exception thrown
3920 * This is a VM internal routine.
3922 * We call this function when we detect an unhandled exception
3923 * in the default domain.
3925 * It invokes the * UnhandledException event in AppDomain or prints
3926 * a warning to the console
3929 mono_unhandled_exception (MonoObject *exc)
3931 MonoDomain *current_domain = mono_domain_get ();
3932 MonoDomain *root_domain = mono_get_root_domain ();
3933 MonoClassField *field;
3934 MonoObject *current_appdomain_delegate;
3935 MonoObject *root_appdomain_delegate;
3937 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3938 "UnhandledException");
3941 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3942 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3943 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3944 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3945 if (current_domain != root_domain) {
3946 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3948 current_appdomain_delegate = NULL;
3951 /* set exitcode only if we will abort the process */
3952 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3954 mono_environment_exitcode_set (1);
3955 mono_print_unhandled_exception (exc);
3957 if (root_appdomain_delegate) {
3958 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3960 if (current_appdomain_delegate) {
3961 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3968 * mono_runtime_exec_managed_code:
3969 * @domain: Application domain
3970 * @main_func: function to invoke from the execution thread
3971 * @main_args: parameter to the main_func
3973 * Launch a new thread to execute a function
3975 * main_func is called back from the thread with main_args as the
3976 * parameter. The callback function is expected to start Main()
3977 * eventually. This function then waits for all managed threads to
3979 * It is not necesseray anymore to execute managed code in a subthread,
3980 * so this function should not be used anymore by default: just
3981 * execute the code and then call mono_thread_manage ().
3984 mono_runtime_exec_managed_code (MonoDomain *domain,
3985 MonoMainThreadFunc main_func,
3988 mono_thread_create (domain, main_func, main_args);
3990 mono_thread_manage ();
3994 * Execute a standard Main() method (args doesn't contain the
3998 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4003 MonoCustomAttrInfo* cinfo;
4004 gboolean has_stathread_attribute;
4005 MonoInternalThread* thread = mono_thread_internal_current ();
4011 domain = mono_object_domain (args);
4012 if (!domain->entry_assembly) {
4014 MonoAssembly *assembly;
4016 assembly = method->klass->image->assembly;
4017 domain->entry_assembly = assembly;
4018 /* Domains created from another domain already have application_base and configuration_file set */
4019 if (domain->setup->application_base == NULL) {
4020 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4023 if (domain->setup->configuration_file == NULL) {
4024 str = g_strconcat (assembly->image->name, ".config", NULL);
4025 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4027 mono_set_private_bin_path_from_config (domain);
4031 cinfo = mono_custom_attrs_from_method (method);
4033 static MonoClass *stathread_attribute = NULL;
4034 if (!stathread_attribute)
4035 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4036 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4038 mono_custom_attrs_free (cinfo);
4040 has_stathread_attribute = FALSE;
4042 if (has_stathread_attribute) {
4043 thread->apartment_state = ThreadApartmentState_STA;
4045 thread->apartment_state = ThreadApartmentState_MTA;
4047 mono_thread_init_apartment_state ();
4049 /* FIXME: check signature of method */
4050 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4052 res = mono_runtime_invoke (method, NULL, pa, exc);
4054 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4058 mono_environment_exitcode_set (rval);
4060 mono_runtime_invoke (method, NULL, pa, exc);
4064 /* If the return type of Main is void, only
4065 * set the exitcode if an exception was thrown
4066 * (we don't want to blow away an
4067 * explicitly-set exit code)
4070 mono_environment_exitcode_set (rval);
4078 * mono_install_runtime_invoke:
4079 * @func: Function to install
4081 * This is a VM internal routine
4084 mono_install_runtime_invoke (MonoInvokeFunc func)
4086 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4091 * mono_runtime_invoke_array:
4092 * @method: method to invoke
4093 * @obJ: object instance
4094 * @params: arguments to the method
4095 * @exc: exception information.
4097 * Invokes the method represented by @method on the object @obj.
4099 * obj is the 'this' pointer, it should be NULL for static
4100 * methods, a MonoObject* for object instances and a pointer to
4101 * the value type for value types.
4103 * The params array contains the arguments to the method with the
4104 * same convention: MonoObject* pointers for object instances and
4105 * pointers to the value type otherwise. The _invoke_array
4106 * variant takes a C# object[] as the params argument (MonoArray
4107 * *params): in this case the value types are boxed inside the
4108 * respective reference representation.
4110 * From unmanaged code you'll usually use the
4111 * mono_runtime_invoke() variant.
4113 * Note that this function doesn't handle virtual methods for
4114 * you, it will exec the exact method you pass: we still need to
4115 * expose a function to lookup the derived class implementation
4116 * of a virtual method (there are examples of this in the code,
4119 * You can pass NULL as the exc argument if you don't want to
4120 * catch exceptions, otherwise, *exc will be set to the exception
4121 * thrown, if any. if an exception is thrown, you can't use the
4122 * MonoObject* result from the function.
4124 * If the method returns a value type, it is boxed in an object
4128 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4131 MonoMethodSignature *sig = mono_method_signature (method);
4132 gpointer *pa = NULL;
4135 gboolean has_byref_nullables = FALSE;
4137 if (NULL != params) {
4138 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4139 for (i = 0; i < mono_array_length (params); i++) {
4140 MonoType *t = sig->params [i];
4146 case MONO_TYPE_BOOLEAN:
4149 case MONO_TYPE_CHAR:
4158 case MONO_TYPE_VALUETYPE:
4159 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4160 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4161 pa [i] = mono_array_get (params, MonoObject*, i);
4163 has_byref_nullables = TRUE;
4165 /* MS seems to create the objects if a null is passed in */
4166 if (!mono_array_get (params, MonoObject*, i))
4167 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4171 * We can't pass the unboxed vtype byref to the callee, since
4172 * that would mean the callee would be able to modify boxed
4173 * primitive types. So we (and MS) make a copy of the boxed
4174 * object, pass that to the callee, and replace the original
4175 * boxed object in the arg array with the copy.
4177 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4178 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4179 mono_array_setref (params, i, copy);
4182 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4185 case MONO_TYPE_STRING:
4186 case MONO_TYPE_OBJECT:
4187 case MONO_TYPE_CLASS:
4188 case MONO_TYPE_ARRAY:
4189 case MONO_TYPE_SZARRAY:
4191 pa [i] = mono_array_addr (params, MonoObject*, i);
4192 // FIXME: I need to check this code path
4194 pa [i] = mono_array_get (params, MonoObject*, i);
4196 case MONO_TYPE_GENERICINST:
4198 t = &t->data.generic_class->container_class->this_arg;
4200 t = &t->data.generic_class->container_class->byval_arg;
4202 case MONO_TYPE_PTR: {
4205 /* The argument should be an IntPtr */
4206 arg = mono_array_get (params, MonoObject*, i);
4210 g_assert (arg->vtable->klass == mono_defaults.int_class);
4211 pa [i] = ((MonoIntPtr*)arg)->m_value;
4216 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4221 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4224 if (mono_class_is_nullable (method->klass)) {
4225 /* Need to create a boxed vtype instead */
4231 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4235 obj = mono_object_new (mono_domain_get (), method->klass);
4236 g_assert (obj); /*maybe we should raise a TLE instead?*/
4237 #ifndef DISABLE_REMOTING
4238 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4239 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4242 if (method->klass->valuetype)
4243 o = mono_object_unbox (obj);
4246 } else if (method->klass->valuetype) {
4247 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4250 mono_runtime_invoke (method, o, pa, exc);
4253 if (mono_class_is_nullable (method->klass)) {
4254 MonoObject *nullable;
4256 /* Convert the unboxed vtype into a Nullable structure */
4257 nullable = mono_object_new (mono_domain_get (), method->klass);
4259 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4260 obj = mono_object_unbox (nullable);
4263 /* obj must be already unboxed if needed */
4264 res = mono_runtime_invoke (method, obj, pa, exc);
4266 if (sig->ret->type == MONO_TYPE_PTR) {
4267 MonoClass *pointer_class;
4268 static MonoMethod *box_method;
4270 MonoObject *box_exc;
4273 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4274 * convert it to a Pointer object.
4276 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4278 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4280 g_assert (res->vtable->klass == mono_defaults.int_class);
4281 box_args [0] = ((MonoIntPtr*)res)->m_value;
4282 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4283 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4284 g_assert (!box_exc);
4287 if (has_byref_nullables) {
4289 * The runtime invoke wrapper already converted byref nullables back,
4290 * and stored them in pa, we just need to copy them back to the
4293 for (i = 0; i < mono_array_length (params); i++) {
4294 MonoType *t = sig->params [i];
4296 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4297 mono_array_setref (params, i, pa [i]);
4306 arith_overflow (void)
4308 mono_raise_exception (mono_get_exception_overflow ());
4312 * mono_object_allocate:
4313 * @size: number of bytes to allocate
4315 * This is a very simplistic routine until we have our GC-aware
4318 * Returns: an allocated object of size @size, or NULL on failure.
4320 static inline void *
4321 mono_object_allocate (size_t size, MonoVTable *vtable)
4324 mono_stats.new_object_count++;
4325 ALLOC_OBJECT (o, vtable, size);
4331 * mono_object_allocate_ptrfree:
4332 * @size: number of bytes to allocate
4334 * Note that the memory allocated is not zeroed.
4335 * Returns: an allocated object of size @size, or NULL on failure.
4337 static inline void *
4338 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4341 mono_stats.new_object_count++;
4342 ALLOC_PTRFREE (o, vtable, size);
4346 static inline void *
4347 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4350 ALLOC_TYPED (o, size, vtable);
4351 mono_stats.new_object_count++;
4358 * @klass: the class of the object that we want to create
4360 * Returns: a newly created object whose definition is
4361 * looked up using @klass. This will not invoke any constructors,
4362 * so the consumer of this routine has to invoke any constructors on
4363 * its own to initialize the object.
4365 * It returns NULL on failure.
4368 mono_object_new (MonoDomain *domain, MonoClass *klass)
4372 MONO_ARCH_SAVE_REGS;
4373 vtable = mono_class_vtable (domain, klass);
4376 return mono_object_new_specific (vtable);
4380 * mono_object_new_pinned:
4382 * Same as mono_object_new, but the returned object will be pinned.
4383 * For SGEN, these objects will only be freed at appdomain unload.
4386 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4390 MONO_ARCH_SAVE_REGS;
4391 vtable = mono_class_vtable (domain, klass);
4396 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4398 return mono_object_new_specific (vtable);
4403 * mono_object_new_specific:
4404 * @vtable: the vtable of the object that we want to create
4406 * Returns: A newly created object with class and domain specified
4410 mono_object_new_specific (MonoVTable *vtable)
4414 MONO_ARCH_SAVE_REGS;
4416 /* check for is_com_object for COM Interop */
4417 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4420 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4423 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4426 mono_class_init (klass);
4428 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4430 vtable->domain->create_proxy_for_type_method = im;
4433 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4435 o = mono_runtime_invoke (im, NULL, pa, NULL);
4436 if (o != NULL) return o;
4439 return mono_object_new_alloc_specific (vtable);
4443 mono_object_new_alloc_specific (MonoVTable *vtable)
4447 if (!vtable->klass->has_references) {
4448 o = mono_object_new_ptrfree (vtable);
4449 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4450 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4452 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4453 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4455 if (G_UNLIKELY (vtable->klass->has_finalize))
4456 mono_object_register_finalizer (o);
4458 if (G_UNLIKELY (profile_allocs))
4459 mono_profiler_allocation (o, vtable->klass);
4464 mono_object_new_fast (MonoVTable *vtable)
4467 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4472 mono_object_new_ptrfree (MonoVTable *vtable)
4475 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4476 #if NEED_TO_ZERO_PTRFREE
4477 /* an inline memset is much faster for the common vcase of small objects
4478 * note we assume the allocated size is a multiple of sizeof (void*).
4480 if (vtable->klass->instance_size < 128) {
4482 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4483 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4489 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4496 mono_object_new_ptrfree_box (MonoVTable *vtable)
4499 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4500 /* the object will be boxed right away, no need to memzero it */
4505 * mono_class_get_allocation_ftn:
4507 * @for_box: the object will be used for boxing
4508 * @pass_size_in_words:
4510 * Return the allocation function appropriate for the given class.
4514 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4516 *pass_size_in_words = FALSE;
4518 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4519 profile_allocs = FALSE;
4521 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4522 return mono_object_new_specific;
4524 if (!vtable->klass->has_references) {
4525 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4527 return mono_object_new_ptrfree_box;
4528 return mono_object_new_ptrfree;
4531 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4533 return mono_object_new_fast;
4536 * FIXME: This is actually slower than mono_object_new_fast, because
4537 * of the overhead of parameter passing.
4540 *pass_size_in_words = TRUE;
4541 #ifdef GC_REDIRECT_TO_LOCAL
4542 return GC_local_gcj_fast_malloc;
4544 return GC_gcj_fast_malloc;
4549 return mono_object_new_specific;
4553 * mono_object_new_from_token:
4554 * @image: Context where the type_token is hosted
4555 * @token: a token of the type that we want to create
4557 * Returns: A newly created object whose definition is
4558 * looked up using @token in the @image image
4561 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4565 class = mono_class_get (image, token);
4567 return mono_object_new (domain, class);
4572 * mono_object_clone:
4573 * @obj: the object to clone
4575 * Returns: A newly created object who is a shallow copy of @obj
4578 mono_object_clone (MonoObject *obj)
4581 int size = obj->vtable->klass->instance_size;
4583 if (obj->vtable->klass->rank)
4584 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4586 o = mono_object_allocate (size, obj->vtable);
4588 if (obj->vtable->klass->has_references) {
4589 mono_gc_wbarrier_object_copy (o, obj);
4591 int size = obj->vtable->klass->instance_size;
4592 /* do not copy the sync state */
4593 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4595 if (G_UNLIKELY (profile_allocs))
4596 mono_profiler_allocation (o, obj->vtable->klass);
4598 if (obj->vtable->klass->has_finalize)
4599 mono_object_register_finalizer (o);
4604 * mono_array_full_copy:
4605 * @src: source array to copy
4606 * @dest: destination array
4608 * Copies the content of one array to another with exactly the same type and size.
4611 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4614 MonoClass *klass = src->obj.vtable->klass;
4616 MONO_ARCH_SAVE_REGS;
4618 g_assert (klass == dest->obj.vtable->klass);
4620 size = mono_array_length (src);
4621 g_assert (size == mono_array_length (dest));
4622 size *= mono_array_element_size (klass);
4624 if (klass->element_class->valuetype) {
4625 if (klass->element_class->has_references)
4626 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4628 mono_gc_memmove (&dest->vector, &src->vector, size);
4630 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4633 mono_gc_memmove (&dest->vector, &src->vector, size);
4638 * mono_array_clone_in_domain:
4639 * @domain: the domain in which the array will be cloned into
4640 * @array: the array to clone
4642 * This routine returns a copy of the array that is hosted on the
4643 * specified MonoDomain.
4646 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4651 MonoClass *klass = array->obj.vtable->klass;
4653 MONO_ARCH_SAVE_REGS;
4655 if (array->bounds == NULL) {
4656 size = mono_array_length (array);
4657 o = mono_array_new_full (domain, klass, &size, NULL);
4659 size *= mono_array_element_size (klass);
4661 if (klass->element_class->valuetype) {
4662 if (klass->element_class->has_references)
4663 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4665 mono_gc_memmove (&o->vector, &array->vector, size);
4667 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4670 mono_gc_memmove (&o->vector, &array->vector, size);
4675 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4676 size = mono_array_element_size (klass);
4677 for (i = 0; i < klass->rank; ++i) {
4678 sizes [i] = array->bounds [i].length;
4679 size *= array->bounds [i].length;
4680 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4682 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4684 if (klass->element_class->valuetype) {
4685 if (klass->element_class->has_references)
4686 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4688 mono_gc_memmove (&o->vector, &array->vector, size);
4690 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4693 mono_gc_memmove (&o->vector, &array->vector, size);
4701 * @array: the array to clone
4703 * Returns: A newly created array who is a shallow copy of @array
4706 mono_array_clone (MonoArray *array)
4708 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4711 /* helper macros to check for overflow when calculating the size of arrays */
4712 #ifdef MONO_BIG_ARRAYS
4713 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4714 #define MYGUINT_MAX MYGUINT64_MAX
4715 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4716 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4717 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4718 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4719 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4721 #define MYGUINT32_MAX 4294967295U
4722 #define MYGUINT_MAX MYGUINT32_MAX
4723 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4724 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4725 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4726 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4727 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4731 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4735 byte_len = mono_array_element_size (class);
4736 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4739 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4741 byte_len += sizeof (MonoArray);
4749 * mono_array_new_full:
4750 * @domain: domain where the object is created
4751 * @array_class: array class
4752 * @lengths: lengths for each dimension in the array
4753 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4755 * This routine creates a new array objects with the given dimensions,
4756 * lower bounds and type.
4759 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4761 uintptr_t byte_len, len, bounds_size;
4764 MonoArrayBounds *bounds;
4768 if (!array_class->inited)
4769 mono_class_init (array_class);
4773 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4774 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4776 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4780 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4782 for (i = 0; i < array_class->rank; ++i) {
4783 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4785 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4786 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4791 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4792 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4796 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4797 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4798 byte_len = (byte_len + 3) & ~3;
4799 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4800 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4801 byte_len += bounds_size;
4804 * Following three lines almost taken from mono_object_new ():
4805 * they need to be kept in sync.
4807 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4808 #ifndef HAVE_SGEN_GC
4809 if (!array_class->has_references) {
4810 o = mono_object_allocate_ptrfree (byte_len, vtable);
4811 #if NEED_TO_ZERO_PTRFREE
4812 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4814 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4815 o = mono_object_allocate_spec (byte_len, vtable);
4817 o = mono_object_allocate (byte_len, vtable);
4820 array = (MonoArray*)o;
4821 array->max_length = len;
4824 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4825 array->bounds = bounds;
4829 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4831 o = mono_gc_alloc_vector (vtable, byte_len, len);
4832 array = (MonoArray*)o;
4833 mono_stats.new_object_count++;
4835 bounds = array->bounds;
4839 for (i = 0; i < array_class->rank; ++i) {
4840 bounds [i].length = lengths [i];
4842 bounds [i].lower_bound = lower_bounds [i];
4846 if (G_UNLIKELY (profile_allocs))
4847 mono_profiler_allocation (o, array_class);
4854 * @domain: domain where the object is created
4855 * @eclass: element class
4856 * @n: number of array elements
4858 * This routine creates a new szarray with @n elements of type @eclass.
4861 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4865 MONO_ARCH_SAVE_REGS;
4867 ac = mono_array_class_get (eclass, 1);
4870 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4874 * mono_array_new_specific:
4875 * @vtable: a vtable in the appropriate domain for an initialized class
4876 * @n: number of array elements
4878 * This routine is a fast alternative to mono_array_new() for code which
4879 * can be sure about the domain it operates in.
4882 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4888 MONO_ARCH_SAVE_REGS;
4890 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4895 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4896 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4899 #ifndef HAVE_SGEN_GC
4900 if (!vtable->klass->has_references) {
4901 o = mono_object_allocate_ptrfree (byte_len, vtable);
4902 #if NEED_TO_ZERO_PTRFREE
4903 ((MonoArray*)o)->bounds = NULL;
4904 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4906 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4907 o = mono_object_allocate_spec (byte_len, vtable);
4909 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4910 o = mono_object_allocate (byte_len, vtable);
4913 ao = (MonoArray *)o;
4916 o = mono_gc_alloc_vector (vtable, byte_len, n);
4918 mono_stats.new_object_count++;
4921 if (G_UNLIKELY (profile_allocs))
4922 mono_profiler_allocation (o, vtable->klass);
4928 * mono_string_new_utf16:
4929 * @text: a pointer to an utf16 string
4930 * @len: the length of the string
4932 * Returns: A newly created string object which contains @text.
4935 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4939 s = mono_string_new_size (domain, len);
4940 g_assert (s != NULL);
4942 memcpy (mono_string_chars (s), text, len * 2);
4948 * mono_string_new_size:
4949 * @text: a pointer to an utf16 string
4950 * @len: the length of the string
4952 * Returns: A newly created string object of @len
4955 mono_string_new_size (MonoDomain *domain, gint32 len)
4959 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4961 /* overflow ? can't fit it, can't allocate it! */
4963 mono_gc_out_of_memory (-1);
4965 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4968 #ifndef HAVE_SGEN_GC
4969 s = mono_object_allocate_ptrfree (size, vtable);
4973 s = mono_gc_alloc_string (vtable, size, len);
4975 #if NEED_TO_ZERO_PTRFREE
4978 if (G_UNLIKELY (profile_allocs))
4979 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4985 * mono_string_new_len:
4986 * @text: a pointer to an utf8 string
4987 * @length: number of bytes in @text to consider
4989 * Returns: A newly created string object which contains @text.
4992 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4994 GError *error = NULL;
4995 MonoString *o = NULL;
4997 glong items_written;
4999 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5002 o = mono_string_new_utf16 (domain, ut, items_written);
5004 g_error_free (error);
5013 * @text: a pointer to an utf8 string
5015 * Returns: A newly created string object which contains @text.
5018 mono_string_new (MonoDomain *domain, const char *text)
5020 GError *error = NULL;
5021 MonoString *o = NULL;
5023 glong items_written;
5028 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5031 o = mono_string_new_utf16 (domain, ut, items_written);
5033 g_error_free (error);
5036 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5041 MonoString *o = NULL;
5043 if (!g_utf8_validate (text, -1, &end))
5046 len = g_utf8_strlen (text, -1);
5047 o = mono_string_new_size (domain, len);
5048 str = mono_string_chars (o);
5050 while (text < end) {
5051 *str++ = g_utf8_get_char (text);
5052 text = g_utf8_next_char (text);
5059 * mono_string_new_wrapper:
5060 * @text: pointer to utf8 characters.
5062 * Helper function to create a string object from @text in the current domain.
5065 mono_string_new_wrapper (const char *text)
5067 MonoDomain *domain = mono_domain_get ();
5069 MONO_ARCH_SAVE_REGS;
5072 return mono_string_new (domain, text);
5079 * @class: the class of the value
5080 * @value: a pointer to the unboxed data
5082 * Returns: A newly created object which contains @value.
5085 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5091 g_assert (class->valuetype);
5092 if (mono_class_is_nullable (class))
5093 return mono_nullable_box (value, class);
5095 vtable = mono_class_vtable (domain, class);
5098 size = mono_class_instance_size (class);
5099 res = mono_object_new_alloc_specific (vtable);
5100 if (G_UNLIKELY (profile_allocs))
5101 mono_profiler_allocation (res, class);
5103 size = size - sizeof (MonoObject);
5106 g_assert (size == mono_class_value_size (class, NULL));
5107 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5109 #if NO_UNALIGNED_ACCESS
5110 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5114 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5117 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5120 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5123 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5126 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5130 if (class->has_finalize)
5131 mono_object_register_finalizer (res);
5137 * @dest: destination pointer
5138 * @src: source pointer
5139 * @klass: a valuetype class
5141 * Copy a valuetype from @src to @dest. This function must be used
5142 * when @klass contains references fields.
5145 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5147 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5151 * mono_value_copy_array:
5152 * @dest: destination array
5153 * @dest_idx: index in the @dest array
5154 * @src: source pointer
5155 * @count: number of items
5157 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5158 * This function must be used when @klass contains references fields.
5159 * Overlap is handled.
5162 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5164 int size = mono_array_element_size (dest->obj.vtable->klass);
5165 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5166 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5167 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5171 * mono_object_get_domain:
5172 * @obj: object to query
5174 * Returns: the MonoDomain where the object is hosted
5177 mono_object_get_domain (MonoObject *obj)
5179 return mono_object_domain (obj);
5183 * mono_object_get_class:
5184 * @obj: object to query
5186 * Returns: the MonOClass of the object.
5189 mono_object_get_class (MonoObject *obj)
5191 return mono_object_class (obj);
5194 * mono_object_get_size:
5195 * @o: object to query
5197 * Returns: the size, in bytes, of @o
5200 mono_object_get_size (MonoObject* o)
5202 MonoClass* klass = mono_object_class (o);
5203 if (klass == mono_defaults.string_class) {
5204 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5205 } else if (o->vtable->rank) {
5206 MonoArray *array = (MonoArray*)o;
5207 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5208 if (array->bounds) {
5211 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5215 return mono_class_instance_size (klass);
5220 * mono_object_unbox:
5221 * @obj: object to unbox
5223 * Returns: a pointer to the start of the valuetype boxed in this
5226 * This method will assert if the object passed is not a valuetype.
5229 mono_object_unbox (MonoObject *obj)
5231 /* add assert for valuetypes? */
5232 g_assert (obj->vtable->klass->valuetype);
5233 return ((char*)obj) + sizeof (MonoObject);
5237 * mono_object_isinst:
5239 * @klass: a pointer to a class
5241 * Returns: @obj if @obj is derived from @klass
5244 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5247 mono_class_init (klass);
5249 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5250 return mono_object_isinst_mbyref (obj, klass);
5255 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5259 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5268 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5269 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5273 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5274 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5277 MonoClass *oklass = vt->klass;
5278 if (mono_class_is_transparent_proxy (oklass))
5279 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5281 mono_class_setup_supertypes (klass);
5282 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5285 #ifndef DISABLE_REMOTING
5286 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5288 MonoDomain *domain = mono_domain_get ();
5290 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5291 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5292 MonoMethod *im = NULL;
5295 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5296 im = mono_object_get_virtual_method (rp, im);
5299 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5302 res = mono_runtime_invoke (im, rp, pa, NULL);
5304 if (*(MonoBoolean *) mono_object_unbox(res)) {
5305 /* Update the vtable of the remote type, so it can safely cast to this new type */
5306 mono_upgrade_remote_class (domain, obj, klass);
5310 #endif /* DISABLE_REMOTING */
5315 * mono_object_castclass_mbyref:
5317 * @klass: a pointer to a class
5319 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5322 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5324 if (!obj) return NULL;
5325 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5327 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5329 "InvalidCastException"));
5334 MonoDomain *orig_domain;
5340 str_lookup (MonoDomain *domain, gpointer user_data)
5342 LDStrInfo *info = user_data;
5343 if (info->res || domain == info->orig_domain)
5345 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5351 mono_string_get_pinned (MonoString *str)
5355 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5356 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5358 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5359 news->length = mono_string_length (str);
5365 #define mono_string_get_pinned(str) (str)
5369 mono_string_is_interned_lookup (MonoString *str, int insert)
5371 MonoGHashTable *ldstr_table;
5375 domain = ((MonoObject *)str)->vtable->domain;
5376 ldstr_table = domain->ldstr_table;
5378 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5383 str = mono_string_get_pinned (str);
5385 mono_g_hash_table_insert (ldstr_table, str, str);
5389 LDStrInfo ldstr_info;
5390 ldstr_info.orig_domain = domain;
5391 ldstr_info.ins = str;
5392 ldstr_info.res = NULL;
5394 mono_domain_foreach (str_lookup, &ldstr_info);
5395 if (ldstr_info.res) {
5397 * the string was already interned in some other domain:
5398 * intern it in the current one as well.
5400 mono_g_hash_table_insert (ldstr_table, str, str);
5410 * mono_string_is_interned:
5411 * @o: String to probe
5413 * Returns whether the string has been interned.
5416 mono_string_is_interned (MonoString *o)
5418 return mono_string_is_interned_lookup (o, FALSE);
5422 * mono_string_intern:
5423 * @o: String to intern
5425 * Interns the string passed.
5426 * Returns: The interned string.
5429 mono_string_intern (MonoString *str)
5431 return mono_string_is_interned_lookup (str, TRUE);
5436 * @domain: the domain where the string will be used.
5437 * @image: a metadata context
5438 * @idx: index into the user string table.
5440 * Implementation for the ldstr opcode.
5441 * Returns: a loaded string from the @image/@idx combination.
5444 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5446 MONO_ARCH_SAVE_REGS;
5448 if (image->dynamic) {
5449 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5452 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5453 return NULL; /*FIXME we should probably be raising an exception here*/
5454 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5459 * mono_ldstr_metadata_sig
5460 * @domain: the domain for the string
5461 * @sig: the signature of a metadata string
5463 * Returns: a MonoString for a string stored in the metadata
5466 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5468 const char *str = sig;
5469 MonoString *o, *interned;
5472 len2 = mono_metadata_decode_blob_size (str, &str);
5475 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5476 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5479 guint16 *p2 = (guint16*)mono_string_chars (o);
5480 for (i = 0; i < len2; ++i) {
5481 *p2 = GUINT16_FROM_LE (*p2);
5487 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5489 /* o will get garbage collected */
5493 o = mono_string_get_pinned (o);
5495 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5502 * mono_string_to_utf8:
5503 * @s: a System.String
5505 * Returns the UTF8 representation for @s.
5506 * The resulting buffer needs to be freed with mono_free().
5508 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5511 mono_string_to_utf8 (MonoString *s)
5514 char *result = mono_string_to_utf8_checked (s, &error);
5516 if (!mono_error_ok (&error))
5517 mono_error_raise_exception (&error);
5522 * mono_string_to_utf8_checked:
5523 * @s: a System.String
5524 * @error: a MonoError.
5526 * Converts a MonoString to its UTF8 representation. May fail; check
5527 * @error to determine whether the conversion was successful.
5528 * The resulting buffer should be freed with mono_free().
5531 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5535 GError *gerror = NULL;
5537 mono_error_init (error);
5543 return g_strdup ("");
5545 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5547 mono_error_set_argument (error, "string", "%s", gerror->message);
5548 g_error_free (gerror);
5551 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5552 if (s->length > written) {
5553 /* allocate the total length and copy the part of the string that has been converted */
5554 char *as2 = g_malloc0 (s->length);
5555 memcpy (as2, as, written);
5564 * mono_string_to_utf8_ignore:
5567 * Converts a MonoString to its UTF8 representation. Will ignore
5568 * invalid surrogate pairs.
5569 * The resulting buffer should be freed with mono_free().
5573 mono_string_to_utf8_ignore (MonoString *s)
5582 return g_strdup ("");
5584 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
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_image_ignore:
5600 * @s: a System.String
5602 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5605 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5607 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5611 * mono_string_to_utf8_mp_ignore:
5612 * @s: a System.String
5614 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5617 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5619 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5624 * mono_string_to_utf16:
5627 * Return an null-terminated array of the utf-16 chars
5628 * contained in @s. The result must be freed with g_free().
5629 * This is a temporary helper until our string implementation
5630 * is reworked to always include the null terminating char.
5633 mono_string_to_utf16 (MonoString *s)
5640 as = g_malloc ((s->length * 2) + 2);
5641 as [(s->length * 2)] = '\0';
5642 as [(s->length * 2) + 1] = '\0';
5645 return (gunichar2 *)(as);
5648 memcpy (as, mono_string_chars(s), s->length * 2);
5649 return (gunichar2 *)(as);
5653 * mono_string_from_utf16:
5654 * @data: the UTF16 string (LPWSTR) to convert
5656 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5658 * Returns: a MonoString.
5661 mono_string_from_utf16 (gunichar2 *data)
5663 MonoDomain *domain = mono_domain_get ();
5669 while (data [len]) len++;
5671 return mono_string_new_utf16 (domain, data, len);
5676 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5683 r = mono_string_to_utf8_ignore (s);
5685 r = mono_string_to_utf8_checked (s, error);
5686 if (!mono_error_ok (error))
5693 len = strlen (r) + 1;
5695 mp_s = mono_mempool_alloc (mp, len);
5697 mp_s = mono_image_alloc (image, len);
5699 memcpy (mp_s, r, len);
5707 * mono_string_to_utf8_image:
5708 * @s: a System.String
5710 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5713 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5715 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5719 * mono_string_to_utf8_mp:
5720 * @s: a System.String
5722 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5725 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5727 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5731 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5734 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5736 eh_callbacks = *cbs;
5739 MonoRuntimeExceptionHandlingCallbacks *
5740 mono_get_eh_callbacks (void)
5742 return &eh_callbacks;
5746 * mono_raise_exception:
5747 * @ex: exception object
5749 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5752 mono_raise_exception (MonoException *ex)
5755 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5756 * that will cause gcc to omit the function epilog, causing problems when
5757 * the JIT tries to walk the stack, since the return address on the stack
5758 * will point into the next function in the executable, not this one.
5760 eh_callbacks.mono_raise_exception (ex);
5764 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5766 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5770 * mono_wait_handle_new:
5771 * @domain: Domain where the object will be created
5772 * @handle: Handle for the wait handle
5774 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5777 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5779 MonoWaitHandle *res;
5780 gpointer params [1];
5781 static MonoMethod *handle_set;
5783 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5785 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5787 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5789 params [0] = &handle;
5790 mono_runtime_invoke (handle_set, res, params, NULL);
5796 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5798 static MonoClassField *f_os_handle;
5799 static MonoClassField *f_safe_handle;
5801 if (!f_os_handle && !f_safe_handle) {
5802 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5803 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5808 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5812 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5819 mono_runtime_capture_context (MonoDomain *domain)
5821 RuntimeInvokeFunction runtime_invoke;
5823 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5824 MonoMethod *method = mono_get_context_capture_method ();
5825 MonoMethod *wrapper;
5828 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5829 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5830 domain->capture_context_method = mono_compile_method (method);
5833 runtime_invoke = domain->capture_context_runtime_invoke;
5835 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5838 * mono_async_result_new:
5839 * @domain:domain where the object will be created.
5840 * @handle: wait handle.
5841 * @state: state to pass to AsyncResult
5842 * @data: C closure data.
5844 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5845 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5849 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5851 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5852 MonoObject *context = mono_runtime_capture_context (domain);
5853 /* we must capture the execution context from the original thread */
5855 MONO_OBJECT_SETREF (res, execution_context, context);
5856 /* note: result may be null if the flow is suppressed */
5860 MONO_OBJECT_SETREF (res, object_data, object_data);
5861 MONO_OBJECT_SETREF (res, async_state, state);
5863 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5865 res->sync_completed = FALSE;
5866 res->completed = FALSE;
5872 mono_message_init (MonoDomain *domain,
5873 MonoMethodMessage *this,
5874 MonoReflectionMethod *method,
5875 MonoArray *out_args)
5877 static MonoClass *object_array_klass;
5878 static MonoClass *byte_array_klass;
5879 static MonoClass *string_array_klass;
5880 MonoMethodSignature *sig = mono_method_signature (method->method);
5886 if (!object_array_klass) {
5889 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5891 byte_array_klass = klass;
5893 klass = mono_array_class_get (mono_defaults.string_class, 1);
5895 string_array_klass = klass;
5897 klass = mono_array_class_get (mono_defaults.object_class, 1);
5900 mono_atomic_store_release (&object_array_klass, klass);
5903 MONO_OBJECT_SETREF (this, method, method);
5905 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5906 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5907 this->async_result = NULL;
5908 this->call_type = CallType_Sync;
5910 names = g_new (char *, sig->param_count);
5911 mono_method_get_param_names (method->method, (const char **) names);
5912 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5914 for (i = 0; i < sig->param_count; i++) {
5915 name = mono_string_new (domain, names [i]);
5916 mono_array_setref (this->names, i, name);
5920 for (i = 0, j = 0; i < sig->param_count; i++) {
5921 if (sig->params [i]->byref) {
5923 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5924 mono_array_setref (this->args, i, arg);
5928 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5932 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5935 mono_array_set (this->arg_types, guint8, i, arg_type);
5939 #ifndef DISABLE_REMOTING
5941 * mono_remoting_invoke:
5942 * @real_proxy: pointer to a RealProxy object
5943 * @msg: The MonoMethodMessage to execute
5944 * @exc: used to store exceptions
5945 * @out_args: used to store output arguments
5947 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5948 * IMessage interface and it is not trivial to extract results from there. So
5949 * we call an helper method PrivateInvoke instead of calling
5950 * RealProxy::Invoke() directly.
5952 * Returns: the result object.
5955 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5956 MonoObject **exc, MonoArray **out_args)
5958 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5961 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5964 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5966 real_proxy->vtable->domain->private_invoke_method = im;
5969 pa [0] = real_proxy;
5974 return mono_runtime_invoke (im, NULL, pa, exc);
5979 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5980 MonoObject **exc, MonoArray **out_args)
5982 static MonoClass *object_array_klass;
5985 MonoMethodSignature *sig;
5987 int i, j, outarg_count = 0;
5989 #ifndef DISABLE_REMOTING
5990 if (target && mono_object_is_transparent_proxy (target)) {
5991 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5992 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
5993 target = tp->rp->unwrapped_server;
5995 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6000 domain = mono_domain_get ();
6001 method = msg->method->method;
6002 sig = mono_method_signature (method);
6004 for (i = 0; i < sig->param_count; i++) {
6005 if (sig->params [i]->byref)
6009 if (!object_array_klass) {
6012 klass = mono_array_class_get (mono_defaults.object_class, 1);
6015 mono_memory_barrier ();
6016 object_array_klass = klass;
6019 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6020 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6023 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6025 for (i = 0, j = 0; i < sig->param_count; i++) {
6026 if (sig->params [i]->byref) {
6028 arg = mono_array_get (msg->args, gpointer, i);
6029 mono_array_setref (*out_args, j, arg);
6038 * mono_object_to_string:
6040 * @exc: Any exception thrown by ToString (). May be NULL.
6042 * Returns: the result of calling ToString () on an object.
6045 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6047 static MonoMethod *to_string = NULL;
6054 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6056 method = mono_object_get_virtual_method (obj, to_string);
6058 // Unbox value type if needed
6059 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6060 target = mono_object_unbox (obj);
6063 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6067 * mono_print_unhandled_exception:
6068 * @exc: The exception
6070 * Prints the unhandled exception.
6073 mono_print_unhandled_exception (MonoObject *exc)
6076 char *message = (char*)"";
6077 gboolean free_message = FALSE;
6080 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6081 message = g_strdup ("OutOfMemoryException");
6082 free_message = TRUE;
6085 if (((MonoException*)exc)->native_trace_ips) {
6086 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6087 free_message = TRUE;
6089 MonoObject *other_exc = NULL;
6090 str = mono_object_to_string (exc, &other_exc);
6092 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6093 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6095 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6096 original_backtrace, nested_backtrace);
6098 g_free (original_backtrace);
6099 g_free (nested_backtrace);
6100 free_message = TRUE;
6102 message = mono_string_to_utf8_checked (str, &error);
6103 if (!mono_error_ok (&error)) {
6104 mono_error_cleanup (&error);
6105 message = (char *) "";
6107 free_message = TRUE;
6114 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6115 * exc->vtable->klass->name, message);
6117 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6124 * mono_delegate_ctor:
6125 * @this: pointer to an uninitialized delegate object
6126 * @target: target object
6127 * @addr: pointer to native code
6130 * Initialize a delegate and sets a specific method, not the one
6131 * associated with addr. This is useful when sharing generic code.
6132 * In that case addr will most probably not be associated with the
6133 * correct instantiation of the method.
6136 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6138 MonoDelegate *delegate = (MonoDelegate *)this;
6145 delegate->method = method;
6147 class = this->vtable->klass;
6148 mono_stats.delegate_creations++;
6150 #ifndef DISABLE_REMOTING
6151 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6153 method = mono_marshal_get_remoting_invoke (method);
6154 delegate->method_ptr = mono_compile_method (method);
6155 MONO_OBJECT_SETREF (delegate, target, target);
6159 delegate->method_ptr = addr;
6160 MONO_OBJECT_SETREF (delegate, target, target);
6163 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6167 * mono_delegate_ctor:
6168 * @this: pointer to an uninitialized delegate object
6169 * @target: target object
6170 * @addr: pointer to native code
6172 * This is used to initialize a delegate.
6175 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6177 MonoDomain *domain = mono_domain_get ();
6179 MonoMethod *method = NULL;
6183 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6185 if (!ji && domain != mono_get_root_domain ())
6186 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6188 method = mono_jit_info_get_method (ji);
6189 g_assert (!method->klass->generic_container);
6192 mono_delegate_ctor_with_method (this, target, addr, method);
6196 * mono_method_call_message_new:
6197 * @method: method to encapsulate
6198 * @params: parameters to the method
6199 * @invoke: optional, delegate invoke.
6200 * @cb: async callback delegate.
6201 * @state: state passed to the async callback.
6203 * Translates arguments pointers into a MonoMethodMessage.
6206 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6207 MonoDelegate **cb, MonoObject **state)
6209 MonoDomain *domain = mono_domain_get ();
6210 MonoMethodSignature *sig = mono_method_signature (method);
6211 MonoMethodMessage *msg;
6214 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6217 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6218 count = sig->param_count - 2;
6220 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6221 count = sig->param_count;
6224 for (i = 0; i < count; i++) {
6229 if (sig->params [i]->byref)
6230 vpos = *((gpointer *)params [i]);
6234 type = sig->params [i]->type;
6235 class = mono_class_from_mono_type (sig->params [i]);
6237 if (class->valuetype)
6238 arg = mono_value_box (domain, class, vpos);
6240 arg = *((MonoObject **)vpos);
6242 mono_array_setref (msg->args, i, arg);
6245 if (cb != NULL && state != NULL) {
6246 *cb = *((MonoDelegate **)params [i]);
6248 *state = *((MonoObject **)params [i]);
6255 * mono_method_return_message_restore:
6257 * Restore results from message based processing back to arguments pointers
6260 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6262 MonoMethodSignature *sig = mono_method_signature (method);
6263 int i, j, type, size, out_len;
6265 if (out_args == NULL)
6267 out_len = mono_array_length (out_args);
6271 for (i = 0, j = 0; i < sig->param_count; i++) {
6272 MonoType *pt = sig->params [i];
6277 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6279 arg = mono_array_get (out_args, gpointer, j);
6282 g_assert (type != MONO_TYPE_VOID);
6284 if (MONO_TYPE_IS_REFERENCE (pt)) {
6285 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6288 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6289 size = mono_class_value_size (class, NULL);
6290 if (class->has_references)
6291 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6293 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6295 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6296 mono_gc_bzero (*((gpointer *)params [i]), size);
6305 #ifndef DISABLE_REMOTING
6308 * mono_load_remote_field:
6309 * @this: pointer to an object
6310 * @klass: klass of the object containing @field
6311 * @field: the field to load
6312 * @res: a storage to store the result
6314 * This method is called by the runtime on attempts to load fields of
6315 * transparent proxy objects. @this points to such TP, @klass is the class of
6316 * the object containing @field. @res is a storage location which can be
6317 * used to store the result.
6319 * Returns: an address pointing to the value of field.
6322 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6324 static MonoMethod *getter = NULL;
6325 MonoDomain *domain = mono_domain_get ();
6326 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6327 MonoClass *field_class;
6328 MonoMethodMessage *msg;
6329 MonoArray *out_args;
6333 g_assert (mono_object_is_transparent_proxy (this));
6334 g_assert (res != NULL);
6336 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6337 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6342 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6346 field_class = mono_class_from_mono_type (field->type);
6348 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6349 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6350 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6352 full_name = mono_type_get_full_name (klass);
6353 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6354 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6357 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6359 if (exc) mono_raise_exception ((MonoException *)exc);
6361 if (mono_array_length (out_args) == 0)
6364 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6366 if (field_class->valuetype) {
6367 return ((char *)*res) + sizeof (MonoObject);
6373 * mono_load_remote_field_new:
6378 * Missing documentation.
6381 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6383 static MonoMethod *getter = NULL;
6384 MonoDomain *domain = mono_domain_get ();
6385 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6386 MonoClass *field_class;
6387 MonoMethodMessage *msg;
6388 MonoArray *out_args;
6389 MonoObject *exc, *res;
6392 g_assert (mono_object_is_transparent_proxy (this));
6394 field_class = mono_class_from_mono_type (field->type);
6396 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6398 if (field_class->valuetype) {
6399 res = mono_object_new (domain, field_class);
6400 val = ((gchar *) res) + sizeof (MonoObject);
6404 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6409 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6413 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6414 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6416 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6418 full_name = mono_type_get_full_name (klass);
6419 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6420 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6423 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6425 if (exc) mono_raise_exception ((MonoException *)exc);
6427 if (mono_array_length (out_args) == 0)
6430 res = mono_array_get (out_args, MonoObject *, 0);
6436 * mono_store_remote_field:
6437 * @this: pointer to an object
6438 * @klass: klass of the object containing @field
6439 * @field: the field to load
6440 * @val: the value/object to store
6442 * This method is called by the runtime on attempts to store fields of
6443 * transparent proxy objects. @this points to such TP, @klass is the class of
6444 * the object containing @field. @val is the new value to store in @field.
6447 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6449 static MonoMethod *setter = NULL;
6450 MonoDomain *domain = mono_domain_get ();
6451 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6452 MonoClass *field_class;
6453 MonoMethodMessage *msg;
6454 MonoArray *out_args;
6459 g_assert (mono_object_is_transparent_proxy (this));
6461 field_class = mono_class_from_mono_type (field->type);
6463 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6464 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6465 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6470 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6474 if (field_class->valuetype)
6475 arg = mono_value_box (domain, field_class, val);
6477 arg = *((MonoObject **)val);
6480 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6481 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6483 full_name = mono_type_get_full_name (klass);
6484 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6485 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6486 mono_array_setref (msg->args, 2, arg);
6489 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6491 if (exc) mono_raise_exception ((MonoException *)exc);
6495 * mono_store_remote_field_new:
6501 * Missing documentation
6504 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6506 static MonoMethod *setter = NULL;
6507 MonoDomain *domain = mono_domain_get ();
6508 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6509 MonoClass *field_class;
6510 MonoMethodMessage *msg;
6511 MonoArray *out_args;
6515 g_assert (mono_object_is_transparent_proxy (this));
6517 field_class = mono_class_from_mono_type (field->type);
6519 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6520 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6521 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6526 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6530 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6531 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6533 full_name = mono_type_get_full_name (klass);
6534 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6535 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6536 mono_array_setref (msg->args, 2, arg);
6539 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6541 if (exc) mono_raise_exception ((MonoException *)exc);
6546 * mono_create_ftnptr:
6548 * Given a function address, create a function descriptor for it.
6549 * This is only needed on some platforms.
6552 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6554 return callbacks.create_ftnptr (domain, addr);
6558 * mono_get_addr_from_ftnptr:
6560 * Given a pointer to a function descriptor, return the function address.
6561 * This is only needed on some platforms.
6564 mono_get_addr_from_ftnptr (gpointer descr)
6566 return callbacks.get_addr_from_ftnptr (descr);
6570 * mono_string_chars:
6573 * Returns a pointer to the UCS16 characters stored in the MonoString
6576 mono_string_chars (MonoString *s)
6582 * mono_string_length:
6585 * Returns the lenght in characters of the string
6588 mono_string_length (MonoString *s)
6594 * mono_array_length:
6595 * @array: a MonoArray*
6597 * Returns the total number of elements in the array. This works for
6598 * both vectors and multidimensional arrays.
6601 mono_array_length (MonoArray *array)
6603 return array->max_length;
6607 * mono_array_addr_with_size:
6608 * @array: a MonoArray*
6609 * @size: size of the array elements
6610 * @idx: index into the array
6612 * Returns the address of the @idx element in the array.
6615 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6617 return ((char*)(array)->vector) + size * idx;