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, 0, &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 if (mono_class_is_contextbound (class))
2121 /* class_vtable_array keeps an array of created vtables
2123 g_ptr_array_add (domain->class_vtable_array, vt);
2124 /* class->runtime_info is protected by the loader lock, both when
2125 * it it enlarged and when it is stored info.
2129 * Store the vtable in class->runtime_info.
2130 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2132 mono_memory_barrier ();
2134 old_info = class->runtime_info;
2135 if (old_info && old_info->max_domain >= domain->domain_id) {
2136 /* someone already created a large enough runtime info */
2137 old_info->domain_vtables [domain->domain_id] = vt;
2139 int new_size = domain->domain_id;
2141 new_size = MAX (new_size, old_info->max_domain);
2143 /* make the new size a power of two */
2145 while (new_size > i)
2148 /* this is a bounded memory retention issue: may want to
2149 * handle it differently when we'll have a rcu-like system.
2151 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2152 runtime_info->max_domain = new_size - 1;
2153 /* copy the stuff from the older info */
2155 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2157 runtime_info->domain_vtables [domain->domain_id] = vt;
2159 mono_memory_barrier ();
2160 class->runtime_info = runtime_info;
2163 if (class == mono_defaults.monotype_class) {
2164 /*FIXME check for OOM*/
2165 vt->type = mono_type_get_object (domain, &class->byval_arg);
2166 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2167 /* This is unregistered in
2168 unregister_vtable_reflection_type() in
2170 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2173 mono_domain_unlock (domain);
2174 mono_loader_unlock ();
2176 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2177 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2178 mono_raise_exception (mono_class_get_exception_for_failure (class));
2180 /* make sure the parent is initialized */
2181 /*FIXME shouldn't this fail the current type?*/
2183 mono_class_vtable_full (domain, class->parent, raise_on_error);
2188 #ifndef DISABLE_REMOTING
2190 * mono_class_proxy_vtable:
2191 * @domain: the application domain
2192 * @remove_class: the remote class
2194 * Creates a vtable for transparent proxies. It is basically
2195 * a copy of the real vtable of the class wrapped in @remote_class,
2196 * but all function pointers invoke the remoting functions, and
2197 * vtable->klass points to the transparent proxy class, and not to @class.
2200 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2203 MonoVTable *vt, *pvt;
2204 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2206 GSList *extra_interfaces = NULL;
2207 MonoClass *class = remote_class->proxy_class;
2208 gpointer *interface_offsets;
2212 #ifdef COMPRESSED_INTERFACE_BITMAP
2216 vt = mono_class_vtable (domain, class);
2217 g_assert (vt); /*FIXME property handle failure*/
2218 max_interface_id = vt->max_interface_id;
2220 /* Calculate vtable space for extra interfaces */
2221 for (j = 0; j < remote_class->interface_count; j++) {
2222 MonoClass* iclass = remote_class->interfaces[j];
2226 /*FIXME test for interfaces with variant generic arguments*/
2227 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2228 continue; /* interface implemented by the class */
2229 if (g_slist_find (extra_interfaces, iclass))
2232 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2234 method_count = mono_class_num_methods (iclass);
2236 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2237 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2239 for (i = 0; i < ifaces->len; ++i) {
2240 MonoClass *ic = g_ptr_array_index (ifaces, i);
2241 /*FIXME test for interfaces with variant generic arguments*/
2242 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2243 continue; /* interface implemented by the class */
2244 if (g_slist_find (extra_interfaces, ic))
2246 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2247 method_count += mono_class_num_methods (ic);
2249 g_ptr_array_free (ifaces, TRUE);
2252 extra_interface_vtsize += method_count * sizeof (gpointer);
2253 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2257 mono_stats.imt_number_of_tables++;
2258 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2259 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2260 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2262 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2263 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2266 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2268 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2270 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2272 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2273 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2275 pvt->klass = mono_defaults.transparent_proxy_class;
2276 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2277 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2279 /* initialize vtable */
2280 mono_class_setup_vtable (class);
2281 for (i = 0; i < class->vtable_size; ++i) {
2284 if ((cm = class->vtable [i]))
2285 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2287 pvt->vtable [i] = NULL;
2290 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2291 /* create trampolines for abstract methods */
2292 for (k = class; k; k = k->parent) {
2294 gpointer iter = NULL;
2295 while ((m = mono_class_get_methods (k, &iter)))
2296 if (!pvt->vtable [m->slot])
2297 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2301 pvt->max_interface_id = max_interface_id;
2302 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2303 #ifdef COMPRESSED_INTERFACE_BITMAP
2304 bitmap = g_malloc0 (bsize);
2306 bitmap = mono_domain_alloc0 (domain, bsize);
2309 if (! ARCH_USE_IMT) {
2310 /* initialize interface offsets */
2311 for (i = 0; i < class->interface_offsets_count; ++i) {
2312 int interface_id = class->interfaces_packed [i]->interface_id;
2313 int slot = class->interface_offsets_packed [i];
2314 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2317 for (i = 0; i < class->interface_offsets_count; ++i) {
2318 int interface_id = class->interfaces_packed [i]->interface_id;
2319 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2322 if (extra_interfaces) {
2323 int slot = class->vtable_size;
2329 /* Create trampolines for the methods of the interfaces */
2330 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2331 interf = list_item->data;
2333 if (! ARCH_USE_IMT) {
2334 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2336 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2340 while ((cm = mono_class_get_methods (interf, &iter)))
2341 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2343 slot += mono_class_num_methods (interf);
2345 if (! ARCH_USE_IMT) {
2346 g_slist_free (extra_interfaces);
2351 /* Now that the vtable is full, we can actually fill up the IMT */
2352 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2353 if (extra_interfaces) {
2354 g_slist_free (extra_interfaces);
2358 #ifdef COMPRESSED_INTERFACE_BITMAP
2359 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2360 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2361 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2364 pvt->interface_bitmap = bitmap;
2369 #endif /* DISABLE_REMOTING */
2372 * mono_class_field_is_special_static:
2374 * Returns whether @field is a thread/context static field.
2377 mono_class_field_is_special_static (MonoClassField *field)
2379 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2381 if (mono_field_is_deleted (field))
2383 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2384 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2391 * mono_class_field_get_special_static_type:
2392 * @field: The MonoClassField describing the field.
2394 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2395 * SPECIAL_STATIC_NONE otherwise.
2398 mono_class_field_get_special_static_type (MonoClassField *field)
2400 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2401 return SPECIAL_STATIC_NONE;
2402 if (mono_field_is_deleted (field))
2403 return SPECIAL_STATIC_NONE;
2404 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2405 return field_is_special_static (field->parent, field);
2406 return SPECIAL_STATIC_NONE;
2410 * mono_class_has_special_static_fields:
2412 * Returns whenever @klass has any thread/context static fields.
2415 mono_class_has_special_static_fields (MonoClass *klass)
2417 MonoClassField *field;
2421 while ((field = mono_class_get_fields (klass, &iter))) {
2422 g_assert (field->parent == klass);
2423 if (mono_class_field_is_special_static (field))
2430 #ifndef DISABLE_REMOTING
2432 * create_remote_class_key:
2433 * Creates an array of pointers that can be used as a hash key for a remote class.
2434 * The first element of the array is the number of pointers.
2437 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2442 if (remote_class == NULL) {
2443 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2444 key = g_malloc (sizeof(gpointer) * 3);
2445 key [0] = GINT_TO_POINTER (2);
2446 key [1] = mono_defaults.marshalbyrefobject_class;
2447 key [2] = extra_class;
2449 key = g_malloc (sizeof(gpointer) * 2);
2450 key [0] = GINT_TO_POINTER (1);
2451 key [1] = extra_class;
2454 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2455 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2456 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2457 key [1] = remote_class->proxy_class;
2459 // Keep the list of interfaces sorted
2460 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2461 if (extra_class && remote_class->interfaces [i] > extra_class) {
2462 key [j++] = extra_class;
2465 key [j] = remote_class->interfaces [i];
2468 key [j] = extra_class;
2470 // Replace the old class. The interface list is the same
2471 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2472 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2473 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2474 for (i = 0; i < remote_class->interface_count; i++)
2475 key [2 + i] = remote_class->interfaces [i];
2483 * copy_remote_class_key:
2485 * Make a copy of KEY in the domain and return the copy.
2488 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2490 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2491 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2493 memcpy (mp_key, key, key_size);
2499 * mono_remote_class:
2500 * @domain: the application domain
2501 * @class_name: name of the remote class
2503 * Creates and initializes a MonoRemoteClass object for a remote type.
2505 * Can raise an exception on failure.
2508 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2511 MonoRemoteClass *rc;
2512 gpointer* key, *mp_key;
2515 key = create_remote_class_key (NULL, proxy_class);
2517 mono_domain_lock (domain);
2518 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2522 mono_domain_unlock (domain);
2526 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2527 if (!mono_error_ok (&error)) {
2529 mono_domain_unlock (domain);
2530 mono_error_raise_exception (&error);
2533 mp_key = copy_remote_class_key (domain, key);
2537 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2538 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2539 rc->interface_count = 1;
2540 rc->interfaces [0] = proxy_class;
2541 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2543 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2544 rc->interface_count = 0;
2545 rc->proxy_class = proxy_class;
2548 rc->default_vtable = NULL;
2549 rc->xdomain_vtable = NULL;
2550 rc->proxy_class_name = name;
2551 #ifndef DISABLE_PERFCOUNTERS
2552 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2555 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2557 mono_domain_unlock (domain);
2562 * clone_remote_class:
2563 * Creates a copy of the remote_class, adding the provided class or interface
2565 static MonoRemoteClass*
2566 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2568 MonoRemoteClass *rc;
2569 gpointer* key, *mp_key;
2571 key = create_remote_class_key (remote_class, extra_class);
2572 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2578 mp_key = copy_remote_class_key (domain, key);
2582 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2584 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2585 rc->proxy_class = remote_class->proxy_class;
2586 rc->interface_count = remote_class->interface_count + 1;
2588 // Keep the list of interfaces sorted, since the hash key of
2589 // the remote class depends on this
2590 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2591 if (remote_class->interfaces [i] > extra_class && i == j)
2592 rc->interfaces [j++] = extra_class;
2593 rc->interfaces [j] = remote_class->interfaces [i];
2596 rc->interfaces [j] = extra_class;
2598 // Replace the old class. The interface array is the same
2599 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2600 rc->proxy_class = extra_class;
2601 rc->interface_count = remote_class->interface_count;
2602 if (rc->interface_count > 0)
2603 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2606 rc->default_vtable = NULL;
2607 rc->xdomain_vtable = NULL;
2608 rc->proxy_class_name = remote_class->proxy_class_name;
2610 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2616 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2618 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2619 mono_domain_lock (domain);
2620 if (rp->target_domain_id != -1) {
2621 if (remote_class->xdomain_vtable == NULL)
2622 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2623 mono_domain_unlock (domain);
2624 mono_loader_unlock ();
2625 return remote_class->xdomain_vtable;
2627 if (remote_class->default_vtable == NULL) {
2630 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2631 klass = mono_class_from_mono_type (type);
2633 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2634 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2637 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2640 mono_domain_unlock (domain);
2641 mono_loader_unlock ();
2642 return remote_class->default_vtable;
2646 * mono_upgrade_remote_class:
2647 * @domain: the application domain
2648 * @tproxy: the proxy whose remote class has to be upgraded.
2649 * @klass: class to which the remote class can be casted.
2651 * Updates the vtable of the remote class by adding the necessary method slots
2652 * and interface offsets so it can be safely casted to klass. klass can be a
2653 * class or an interface.
2656 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2658 MonoTransparentProxy *tproxy;
2659 MonoRemoteClass *remote_class;
2660 gboolean redo_vtable;
2662 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2663 mono_domain_lock (domain);
2665 tproxy = (MonoTransparentProxy*) proxy_object;
2666 remote_class = tproxy->remote_class;
2668 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2671 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2672 if (remote_class->interfaces [i] == klass)
2673 redo_vtable = FALSE;
2676 redo_vtable = (remote_class->proxy_class != klass);
2680 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2681 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2684 mono_domain_unlock (domain);
2685 mono_loader_unlock ();
2687 #endif /* DISABLE_REMOTING */
2691 * mono_object_get_virtual_method:
2692 * @obj: object to operate on.
2695 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2696 * the instance of a callvirt of method.
2699 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2702 MonoMethod **vtable;
2703 gboolean is_proxy = FALSE;
2704 MonoMethod *res = NULL;
2706 klass = mono_object_class (obj);
2707 #ifndef DISABLE_REMOTING
2708 if (klass == mono_defaults.transparent_proxy_class) {
2709 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2714 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2717 mono_class_setup_vtable (klass);
2718 vtable = klass->vtable;
2720 if (method->slot == -1) {
2721 /* method->slot might not be set for instances of generic methods */
2722 if (method->is_inflated) {
2723 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2724 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2727 g_assert_not_reached ();
2731 /* check method->slot is a valid index: perform isinstance? */
2732 if (method->slot != -1) {
2733 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2735 gboolean variance_used = FALSE;
2736 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2737 g_assert (iface_offset > 0);
2738 res = vtable [iface_offset + method->slot];
2741 res = vtable [method->slot];
2745 #ifndef DISABLE_REMOTING
2747 /* It may be an interface, abstract class method or generic method */
2748 if (!res || mono_method_signature (res)->generic_param_count)
2751 /* generic methods demand invoke_with_check */
2752 if (mono_method_signature (res)->generic_param_count)
2753 res = mono_marshal_get_remoting_invoke_with_check (res);
2756 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2757 res = mono_cominterop_get_invoke (res);
2760 res = mono_marshal_get_remoting_invoke (res);
2765 if (method->is_inflated) {
2766 /* Have to inflate the result */
2767 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2777 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2779 g_error ("runtime invoke called on uninitialized runtime");
2783 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2786 * mono_runtime_invoke:
2787 * @method: method to invoke
2788 * @obJ: object instance
2789 * @params: arguments to the method
2790 * @exc: exception information.
2792 * Invokes the method represented by @method on the object @obj.
2794 * obj is the 'this' pointer, it should be NULL for static
2795 * methods, a MonoObject* for object instances and a pointer to
2796 * the value type for value types.
2798 * The params array contains the arguments to the method with the
2799 * same convention: MonoObject* pointers for object instances and
2800 * pointers to the value type otherwise.
2802 * From unmanaged code you'll usually use the
2803 * mono_runtime_invoke() variant.
2805 * Note that this function doesn't handle virtual methods for
2806 * you, it will exec the exact method you pass: we still need to
2807 * expose a function to lookup the derived class implementation
2808 * of a virtual method (there are examples of this in the code,
2811 * You can pass NULL as the exc argument if you don't want to
2812 * catch exceptions, otherwise, *exc will be set to the exception
2813 * thrown, if any. if an exception is thrown, you can't use the
2814 * MonoObject* result from the function.
2816 * If the method returns a value type, it is boxed in an object
2820 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2824 if (mono_runtime_get_no_exec ())
2825 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2827 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2828 mono_profiler_method_start_invoke (method);
2830 result = default_mono_runtime_invoke (method, obj, params, exc);
2832 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2833 mono_profiler_method_end_invoke (method);
2839 * mono_method_get_unmanaged_thunk:
2840 * @method: method to generate a thunk for.
2842 * Returns an unmanaged->managed thunk that can be used to call
2843 * a managed method directly from C.
2845 * The thunk's C signature closely matches the managed signature:
2847 * C#: public bool Equals (object obj);
2848 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2849 * MonoObject*, MonoException**);
2851 * The 1st ("this") parameter must not be used with static methods:
2853 * C#: public static bool ReferenceEquals (object a, object b);
2854 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2857 * The last argument must be a non-null pointer of a MonoException* pointer.
2858 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2859 * exception has been thrown in managed code. Otherwise it will point
2860 * to the MonoException* caught by the thunk. In this case, the result of
2861 * the thunk is undefined:
2863 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2864 * MonoException *ex = NULL;
2865 * Equals func = mono_method_get_unmanaged_thunk (method);
2866 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2868 * // handle exception
2871 * The calling convention of the thunk matches the platform's default
2872 * convention. This means that under Windows, C declarations must
2873 * contain the __stdcall attribute:
2875 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2876 * MonoObject*, MonoException**);
2880 * Value type arguments and return values are treated as they were objects:
2882 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2883 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2885 * Arguments must be properly boxed upon trunk's invocation, while return
2886 * values must be unboxed.
2889 mono_method_get_unmanaged_thunk (MonoMethod *method)
2891 method = mono_marshal_get_thunk_invoke_wrapper (method);
2892 return mono_compile_method (method);
2896 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2900 /* object fields cannot be byref, so we don't need a
2902 gpointer *p = (gpointer*)dest;
2909 case MONO_TYPE_BOOLEAN:
2911 case MONO_TYPE_U1: {
2912 guint8 *p = (guint8*)dest;
2913 *p = value ? *(guint8*)value : 0;
2918 case MONO_TYPE_CHAR: {
2919 guint16 *p = (guint16*)dest;
2920 *p = value ? *(guint16*)value : 0;
2923 #if SIZEOF_VOID_P == 4
2928 case MONO_TYPE_U4: {
2929 gint32 *p = (gint32*)dest;
2930 *p = value ? *(gint32*)value : 0;
2933 #if SIZEOF_VOID_P == 8
2938 case MONO_TYPE_U8: {
2939 gint64 *p = (gint64*)dest;
2940 *p = value ? *(gint64*)value : 0;
2943 case MONO_TYPE_R4: {
2944 float *p = (float*)dest;
2945 *p = value ? *(float*)value : 0;
2948 case MONO_TYPE_R8: {
2949 double *p = (double*)dest;
2950 *p = value ? *(double*)value : 0;
2953 case MONO_TYPE_STRING:
2954 case MONO_TYPE_SZARRAY:
2955 case MONO_TYPE_CLASS:
2956 case MONO_TYPE_OBJECT:
2957 case MONO_TYPE_ARRAY:
2958 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2960 case MONO_TYPE_FNPTR:
2961 case MONO_TYPE_PTR: {
2962 gpointer *p = (gpointer*)dest;
2963 *p = deref_pointer? *(gpointer*)value: value;
2966 case MONO_TYPE_VALUETYPE:
2967 /* note that 't' and 'type->type' can be different */
2968 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2969 t = mono_class_enum_basetype (type->data.klass)->type;
2972 MonoClass *class = mono_class_from_mono_type (type);
2973 int size = mono_class_value_size (class, NULL);
2975 mono_gc_bzero (dest, size);
2977 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2980 case MONO_TYPE_GENERICINST:
2981 t = type->data.generic_class->container_class->byval_arg.type;
2984 g_error ("got type %x", type->type);
2989 * mono_field_set_value:
2990 * @obj: Instance object
2991 * @field: MonoClassField describing the field to set
2992 * @value: The value to be set
2994 * Sets the value of the field described by @field in the object instance @obj
2995 * to the value passed in @value. This method should only be used for instance
2996 * fields. For static fields, use mono_field_static_set_value.
2998 * The value must be on the native format of the field type.
3001 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3005 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3007 dest = (char*)obj + field->offset;
3008 set_value (field->type, dest, value, FALSE);
3012 * mono_field_static_set_value:
3013 * @field: MonoClassField describing the field to set
3014 * @value: The value to be set
3016 * Sets the value of the static field described by @field
3017 * to the value passed in @value.
3019 * The value must be on the native format of the field type.
3022 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3026 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3027 /* you cant set a constant! */
3028 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3030 if (field->offset == -1) {
3031 /* Special static */
3034 mono_domain_lock (vt->domain);
3035 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3036 mono_domain_unlock (vt->domain);
3037 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3039 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3041 set_value (field->type, dest, value, FALSE);
3045 * mono_vtable_get_static_field_data:
3047 * Internal use function: return a pointer to the memory holding the static fields
3048 * for a class or NULL if there are no static fields.
3049 * This is exported only for use by the debugger.
3052 mono_vtable_get_static_field_data (MonoVTable *vt)
3054 if (!vt->has_static_fields)
3056 return vt->vtable [vt->klass->vtable_size];
3060 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3064 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3065 if (field->offset == -1) {
3066 /* Special static */
3069 mono_domain_lock (vt->domain);
3070 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3071 mono_domain_unlock (vt->domain);
3072 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3074 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3077 src = (guint8*)obj + field->offset;
3084 * mono_field_get_value:
3085 * @obj: Object instance
3086 * @field: MonoClassField describing the field to fetch information from
3087 * @value: pointer to the location where the value will be stored
3089 * Use this routine to get the value of the field @field in the object
3092 * The pointer provided by value must be of the field type, for reference
3093 * types this is a MonoObject*, for value types its the actual pointer to
3098 * mono_field_get_value (obj, int_field, &i);
3101 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3107 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3109 src = (char*)obj + field->offset;
3110 set_value (field->type, value, src, TRUE);
3114 * mono_field_get_value_object:
3115 * @domain: domain where the object will be created (if boxing)
3116 * @field: MonoClassField describing the field to fetch information from
3117 * @obj: The object instance for the field.
3119 * Returns: a new MonoObject with the value from the given field. If the
3120 * field represents a value type, the value is boxed.
3124 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3128 MonoVTable *vtable = NULL;
3130 gboolean is_static = FALSE;
3131 gboolean is_ref = FALSE;
3132 gboolean is_literal = FALSE;
3133 gboolean is_ptr = FALSE;
3135 MonoType *type = mono_field_get_type_checked (field, &error);
3137 if (!mono_error_ok (&error))
3138 mono_error_raise_exception (&error);
3140 switch (type->type) {
3141 case MONO_TYPE_STRING:
3142 case MONO_TYPE_OBJECT:
3143 case MONO_TYPE_CLASS:
3144 case MONO_TYPE_ARRAY:
3145 case MONO_TYPE_SZARRAY:
3150 case MONO_TYPE_BOOLEAN:
3153 case MONO_TYPE_CHAR:
3162 case MONO_TYPE_VALUETYPE:
3163 is_ref = type->byref;
3165 case MONO_TYPE_GENERICINST:
3166 is_ref = !mono_type_generic_inst_is_valuetype (type);
3172 g_error ("type 0x%x not handled in "
3173 "mono_field_get_value_object", type->type);
3177 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3180 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3184 vtable = mono_class_vtable (domain, field->parent);
3186 char *name = mono_type_get_full_name (field->parent);
3187 /*FIXME extend this to use the MonoError api*/
3188 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3192 if (!vtable->initialized)
3193 mono_runtime_class_init (vtable);
3201 get_default_field_value (domain, field, &o);
3202 } else if (is_static) {
3203 mono_field_static_get_value (vtable, field, &o);
3205 mono_field_get_value (obj, field, &o);
3211 static MonoMethod *m;
3217 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3218 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3224 get_default_field_value (domain, field, v);
3225 } else if (is_static) {
3226 mono_field_static_get_value (vtable, field, v);
3228 mono_field_get_value (obj, field, v);
3231 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3233 args [1] = mono_type_get_object (mono_domain_get (), type);
3235 return mono_runtime_invoke (m, NULL, args, NULL);
3238 /* boxed value type */
3239 klass = mono_class_from_mono_type (type);
3241 if (mono_class_is_nullable (klass))
3242 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3244 o = mono_object_new (domain, klass);
3245 v = ((gchar *) o) + sizeof (MonoObject);
3248 get_default_field_value (domain, field, v);
3249 } else if (is_static) {
3250 mono_field_static_get_value (vtable, field, v);
3252 mono_field_get_value (obj, field, v);
3259 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3262 const char *p = blob;
3263 mono_metadata_decode_blob_size (p, &p);
3266 case MONO_TYPE_BOOLEAN:
3269 *(guint8 *) value = *p;
3271 case MONO_TYPE_CHAR:
3274 *(guint16*) value = read16 (p);
3278 *(guint32*) value = read32 (p);
3282 *(guint64*) value = read64 (p);
3285 readr4 (p, (float*) value);
3288 readr8 (p, (double*) value);
3290 case MONO_TYPE_STRING:
3291 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3293 case MONO_TYPE_CLASS:
3294 *(gpointer*) value = NULL;
3298 g_warning ("type 0x%02x should not be in constant table", type);
3304 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3306 MonoTypeEnum def_type;
3309 data = mono_class_get_field_default_value (field, &def_type);
3310 mono_get_constant_value_from_blob (domain, def_type, data, value);
3314 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3318 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3320 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3321 get_default_field_value (vt->domain, field, value);
3325 if (field->offset == -1) {
3326 /* Special static */
3327 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3328 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3330 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3332 set_value (field->type, value, src, TRUE);
3336 * mono_field_static_get_value:
3337 * @vt: vtable to the object
3338 * @field: MonoClassField describing the field to fetch information from
3339 * @value: where the value is returned
3341 * Use this routine to get the value of the static field @field value.
3343 * The pointer provided by value must be of the field type, for reference
3344 * types this is a MonoObject*, for value types its the actual pointer to
3349 * mono_field_static_get_value (vt, int_field, &i);
3352 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3354 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3358 * mono_property_set_value:
3359 * @prop: MonoProperty to set
3360 * @obj: instance object on which to act
3361 * @params: parameters to pass to the propery
3362 * @exc: optional exception
3364 * Invokes the property's set method with the given arguments on the
3365 * object instance obj (or NULL for static properties).
3367 * You can pass NULL as the exc argument if you don't want to
3368 * catch exceptions, otherwise, *exc will be set to the exception
3369 * thrown, if any. if an exception is thrown, you can't use the
3370 * MonoObject* result from the function.
3373 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3375 default_mono_runtime_invoke (prop->set, obj, params, exc);
3379 * mono_property_get_value:
3380 * @prop: MonoProperty to fetch
3381 * @obj: instance object on which to act
3382 * @params: parameters to pass to the propery
3383 * @exc: optional exception
3385 * Invokes the property's get method with the given arguments on the
3386 * object instance obj (or NULL for static properties).
3388 * You can pass NULL as the exc argument if you don't want to
3389 * catch exceptions, otherwise, *exc will be set to the exception
3390 * thrown, if any. if an exception is thrown, you can't use the
3391 * MonoObject* result from the function.
3393 * Returns: the value from invoking the get method on the property.
3396 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3398 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3402 * mono_nullable_init:
3403 * @buf: The nullable structure to initialize.
3404 * @value: the value to initialize from
3405 * @klass: the type for the object
3407 * Initialize the nullable structure pointed to by @buf from @value which
3408 * should be a boxed value type. The size of @buf should be able to hold
3409 * as much data as the @klass->instance_size (which is the number of bytes
3410 * that will be copies).
3412 * Since Nullables have variable structure, we can not define a C
3413 * structure for them.
3416 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3418 MonoClass *param_class = klass->cast_class;
3420 mono_class_setup_fields_locking (klass);
3421 g_assert (klass->fields_inited);
3423 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3424 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3426 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3428 if (param_class->has_references)
3429 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3431 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3433 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3438 * mono_nullable_box:
3439 * @buf: The buffer representing the data to be boxed
3440 * @klass: the type to box it as.
3442 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3446 mono_nullable_box (guint8 *buf, MonoClass *klass)
3448 MonoClass *param_class = klass->cast_class;
3450 mono_class_setup_fields_locking (klass);
3451 g_assert (klass->fields_inited);
3453 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3454 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3456 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3457 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3458 if (param_class->has_references)
3459 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3461 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3469 * mono_get_delegate_invoke:
3470 * @klass: The delegate class
3472 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3475 mono_get_delegate_invoke (MonoClass *klass)
3479 /* This is called at runtime, so avoid the slower search in metadata */
3480 mono_class_setup_methods (klass);
3481 if (klass->exception_type)
3483 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3488 * mono_get_delegate_begin_invoke:
3489 * @klass: The delegate class
3491 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3494 mono_get_delegate_begin_invoke (MonoClass *klass)
3498 /* This is called at runtime, so avoid the slower search in metadata */
3499 mono_class_setup_methods (klass);
3500 if (klass->exception_type)
3502 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3507 * mono_get_delegate_end_invoke:
3508 * @klass: The delegate class
3510 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3513 mono_get_delegate_end_invoke (MonoClass *klass)
3517 /* This is called at runtime, so avoid the slower search in metadata */
3518 mono_class_setup_methods (klass);
3519 if (klass->exception_type)
3521 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3526 * mono_runtime_delegate_invoke:
3527 * @delegate: pointer to a delegate object.
3528 * @params: parameters for the delegate.
3529 * @exc: Pointer to the exception result.
3531 * Invokes the delegate method @delegate with the parameters provided.
3533 * You can pass NULL as the exc argument if you don't want to
3534 * catch exceptions, otherwise, *exc will be set to the exception
3535 * thrown, if any. if an exception is thrown, you can't use the
3536 * MonoObject* result from the function.
3539 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3542 MonoClass *klass = delegate->vtable->klass;
3544 im = mono_get_delegate_invoke (klass);
3546 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3548 return mono_runtime_invoke (im, delegate, params, exc);
3551 static char **main_args = NULL;
3552 static int num_main_args;
3555 * mono_runtime_get_main_args:
3557 * Returns: a MonoArray with the arguments passed to the main program
3560 mono_runtime_get_main_args (void)
3564 MonoDomain *domain = mono_domain_get ();
3569 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3571 for (i = 0; i < num_main_args; ++i)
3572 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3578 free_main_args (void)
3582 for (i = 0; i < num_main_args; ++i)
3583 g_free (main_args [i]);
3588 * mono_runtime_run_main:
3589 * @method: the method to start the application with (usually Main)
3590 * @argc: number of arguments from the command line
3591 * @argv: array of strings from the command line
3592 * @exc: excetption results
3594 * Execute a standard Main() method (argc/argv contains the
3595 * executable name). This method also sets the command line argument value
3596 * needed by System.Environment.
3601 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3605 MonoArray *args = NULL;
3606 MonoDomain *domain = mono_domain_get ();
3607 gchar *utf8_fullpath;
3608 MonoMethodSignature *sig;
3610 g_assert (method != NULL);
3612 mono_thread_set_main (mono_thread_current ());
3614 main_args = g_new0 (char*, argc);
3615 num_main_args = argc;
3617 if (!g_path_is_absolute (argv [0])) {
3618 gchar *basename = g_path_get_basename (argv [0]);
3619 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3623 utf8_fullpath = mono_utf8_from_external (fullpath);
3624 if(utf8_fullpath == NULL) {
3625 /* Printing the arg text will cause glib to
3626 * whinge about "Invalid UTF-8", but at least
3627 * its relevant, and shows the problem text
3630 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3631 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3638 utf8_fullpath = mono_utf8_from_external (argv[0]);
3639 if(utf8_fullpath == NULL) {
3640 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3641 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3646 main_args [0] = utf8_fullpath;
3648 for (i = 1; i < argc; ++i) {
3651 utf8_arg=mono_utf8_from_external (argv[i]);
3652 if(utf8_arg==NULL) {
3653 /* Ditto the comment about Invalid UTF-8 here */
3654 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3655 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3659 main_args [i] = utf8_arg;
3664 sig = mono_method_signature (method);
3666 g_print ("Unable to load Main method.\n");
3670 if (sig->param_count) {
3671 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3672 for (i = 0; i < argc; ++i) {
3673 /* The encodings should all work, given that
3674 * we've checked all these args for the
3677 gchar *str = mono_utf8_from_external (argv [i]);
3678 MonoString *arg = mono_string_new (domain, str);
3679 mono_array_setref (args, i, arg);
3683 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3686 mono_assembly_set_main (method->klass->image->assembly);
3688 return mono_runtime_exec_main (method, args, exc);
3692 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3694 static MonoMethod *serialize_method;
3699 if (!serialize_method) {
3700 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3701 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3704 if (!serialize_method) {
3709 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3713 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3721 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3723 static MonoMethod *deserialize_method;
3728 if (!deserialize_method) {
3729 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3730 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3732 if (!deserialize_method) {
3739 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3746 #ifndef DISABLE_REMOTING
3748 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3750 static MonoMethod *get_proxy_method;
3752 MonoDomain *domain = mono_domain_get ();
3753 MonoRealProxy *real_proxy;
3754 MonoReflectionType *reflection_type;
3755 MonoTransparentProxy *transparent_proxy;
3757 if (!get_proxy_method)
3758 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3760 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3762 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3763 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3765 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3766 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3769 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3773 return (MonoObject*) transparent_proxy;
3775 #endif /* DISABLE_REMOTING */
3778 * mono_object_xdomain_representation
3780 * @target_domain: a domain
3781 * @exc: pointer to a MonoObject*
3783 * Creates a representation of obj in the domain target_domain. This
3784 * is either a copy of obj arrived through via serialization and
3785 * deserialization or a proxy, depending on whether the object is
3786 * serializable or marshal by ref. obj must not be in target_domain.
3788 * If the object cannot be represented in target_domain, NULL is
3789 * returned and *exc is set to an appropriate exception.
3792 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3794 MonoObject *deserialized = NULL;
3795 gboolean failure = FALSE;
3799 #ifndef DISABLE_REMOTING
3800 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3801 deserialized = make_transparent_proxy (obj, &failure, exc);
3806 MonoDomain *domain = mono_domain_get ();
3807 MonoObject *serialized;
3809 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3810 serialized = serialize_object (obj, &failure, exc);
3811 mono_domain_set_internal_with_options (target_domain, FALSE);
3813 deserialized = deserialize_object (serialized, &failure, exc);
3814 if (domain != target_domain)
3815 mono_domain_set_internal_with_options (domain, FALSE);
3818 return deserialized;
3821 /* Used in call_unhandled_exception_delegate */
3823 create_unhandled_exception_eventargs (MonoObject *exc)
3827 MonoMethod *method = NULL;
3828 MonoBoolean is_terminating = TRUE;
3831 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3834 mono_class_init (klass);
3836 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3837 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3841 args [1] = &is_terminating;
3843 obj = mono_object_new (mono_domain_get (), klass);
3844 mono_runtime_invoke (method, obj, args, NULL);
3849 /* Used in mono_unhandled_exception */
3851 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3852 MonoObject *e = NULL;
3854 MonoDomain *current_domain = mono_domain_get ();
3856 if (domain != current_domain)
3857 mono_domain_set_internal_with_options (domain, FALSE);
3859 g_assert (domain == mono_object_domain (domain->domain));
3861 if (mono_object_domain (exc) != domain) {
3862 MonoObject *serialization_exc;
3864 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3866 if (serialization_exc) {
3868 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3871 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3872 "System.Runtime.Serialization", "SerializationException",
3873 "Could not serialize unhandled exception.");
3877 g_assert (mono_object_domain (exc) == domain);
3879 pa [0] = domain->domain;
3880 pa [1] = create_unhandled_exception_eventargs (exc);
3881 mono_runtime_delegate_invoke (delegate, pa, &e);
3883 if (domain != current_domain)
3884 mono_domain_set_internal_with_options (current_domain, FALSE);
3888 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3889 if (!mono_error_ok (&error)) {
3890 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3891 mono_error_cleanup (&error);
3893 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3899 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3902 * mono_runtime_unhandled_exception_policy_set:
3903 * @policy: the new policy
3905 * This is a VM internal routine.
3907 * Sets the runtime policy for handling unhandled exceptions.
3910 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3911 runtime_unhandled_exception_policy = policy;
3915 * mono_runtime_unhandled_exception_policy_get:
3917 * This is a VM internal routine.
3919 * Gets the runtime policy for handling unhandled exceptions.
3921 MonoRuntimeUnhandledExceptionPolicy
3922 mono_runtime_unhandled_exception_policy_get (void) {
3923 return runtime_unhandled_exception_policy;
3927 * mono_unhandled_exception:
3928 * @exc: exception thrown
3930 * This is a VM internal routine.
3932 * We call this function when we detect an unhandled exception
3933 * in the default domain.
3935 * It invokes the * UnhandledException event in AppDomain or prints
3936 * a warning to the console
3939 mono_unhandled_exception (MonoObject *exc)
3941 MonoDomain *current_domain = mono_domain_get ();
3942 MonoDomain *root_domain = mono_get_root_domain ();
3943 MonoClassField *field;
3944 MonoObject *current_appdomain_delegate;
3945 MonoObject *root_appdomain_delegate;
3947 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3948 "UnhandledException");
3951 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3952 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3953 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3954 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3955 if (current_domain != root_domain) {
3956 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3958 current_appdomain_delegate = NULL;
3961 /* set exitcode only if we will abort the process */
3962 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3964 mono_environment_exitcode_set (1);
3965 mono_print_unhandled_exception (exc);
3967 if (root_appdomain_delegate) {
3968 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3970 if (current_appdomain_delegate) {
3971 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3978 * mono_runtime_exec_managed_code:
3979 * @domain: Application domain
3980 * @main_func: function to invoke from the execution thread
3981 * @main_args: parameter to the main_func
3983 * Launch a new thread to execute a function
3985 * main_func is called back from the thread with main_args as the
3986 * parameter. The callback function is expected to start Main()
3987 * eventually. This function then waits for all managed threads to
3989 * It is not necesseray anymore to execute managed code in a subthread,
3990 * so this function should not be used anymore by default: just
3991 * execute the code and then call mono_thread_manage ().
3994 mono_runtime_exec_managed_code (MonoDomain *domain,
3995 MonoMainThreadFunc main_func,
3998 mono_thread_create (domain, main_func, main_args);
4000 mono_thread_manage ();
4004 * Execute a standard Main() method (args doesn't contain the
4008 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4013 MonoCustomAttrInfo* cinfo;
4014 gboolean has_stathread_attribute;
4015 MonoInternalThread* thread = mono_thread_internal_current ();
4021 domain = mono_object_domain (args);
4022 if (!domain->entry_assembly) {
4024 MonoAssembly *assembly;
4026 assembly = method->klass->image->assembly;
4027 domain->entry_assembly = assembly;
4028 /* Domains created from another domain already have application_base and configuration_file set */
4029 if (domain->setup->application_base == NULL) {
4030 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4033 if (domain->setup->configuration_file == NULL) {
4034 str = g_strconcat (assembly->image->name, ".config", NULL);
4035 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4037 mono_set_private_bin_path_from_config (domain);
4041 cinfo = mono_custom_attrs_from_method (method);
4043 static MonoClass *stathread_attribute = NULL;
4044 if (!stathread_attribute)
4045 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4046 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4048 mono_custom_attrs_free (cinfo);
4050 has_stathread_attribute = FALSE;
4052 if (has_stathread_attribute) {
4053 thread->apartment_state = ThreadApartmentState_STA;
4055 thread->apartment_state = ThreadApartmentState_MTA;
4057 mono_thread_init_apartment_state ();
4059 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
4061 /* FIXME: check signature of method */
4062 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4064 res = mono_runtime_invoke (method, NULL, pa, exc);
4066 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4070 mono_environment_exitcode_set (rval);
4072 mono_runtime_invoke (method, NULL, pa, exc);
4076 /* If the return type of Main is void, only
4077 * set the exitcode if an exception was thrown
4078 * (we don't want to blow away an
4079 * explicitly-set exit code)
4082 mono_environment_exitcode_set (rval);
4086 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4092 * mono_install_runtime_invoke:
4093 * @func: Function to install
4095 * This is a VM internal routine
4098 mono_install_runtime_invoke (MonoInvokeFunc func)
4100 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4105 * mono_runtime_invoke_array:
4106 * @method: method to invoke
4107 * @obJ: object instance
4108 * @params: arguments to the method
4109 * @exc: exception information.
4111 * Invokes the method represented by @method on the object @obj.
4113 * obj is the 'this' pointer, it should be NULL for static
4114 * methods, a MonoObject* for object instances and a pointer to
4115 * the value type for value types.
4117 * The params array contains the arguments to the method with the
4118 * same convention: MonoObject* pointers for object instances and
4119 * pointers to the value type otherwise. The _invoke_array
4120 * variant takes a C# object[] as the params argument (MonoArray
4121 * *params): in this case the value types are boxed inside the
4122 * respective reference representation.
4124 * From unmanaged code you'll usually use the
4125 * mono_runtime_invoke() variant.
4127 * Note that this function doesn't handle virtual methods for
4128 * you, it will exec the exact method you pass: we still need to
4129 * expose a function to lookup the derived class implementation
4130 * of a virtual method (there are examples of this in the code,
4133 * You can pass NULL as the exc argument if you don't want to
4134 * catch exceptions, otherwise, *exc will be set to the exception
4135 * thrown, if any. if an exception is thrown, you can't use the
4136 * MonoObject* result from the function.
4138 * If the method returns a value type, it is boxed in an object
4142 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4145 MonoMethodSignature *sig = mono_method_signature (method);
4146 gpointer *pa = NULL;
4149 gboolean has_byref_nullables = FALSE;
4151 if (NULL != params) {
4152 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4153 for (i = 0; i < mono_array_length (params); i++) {
4154 MonoType *t = sig->params [i];
4160 case MONO_TYPE_BOOLEAN:
4163 case MONO_TYPE_CHAR:
4172 case MONO_TYPE_VALUETYPE:
4173 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4174 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4175 pa [i] = mono_array_get (params, MonoObject*, i);
4177 has_byref_nullables = TRUE;
4179 /* MS seems to create the objects if a null is passed in */
4180 if (!mono_array_get (params, MonoObject*, i))
4181 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4185 * We can't pass the unboxed vtype byref to the callee, since
4186 * that would mean the callee would be able to modify boxed
4187 * primitive types. So we (and MS) make a copy of the boxed
4188 * object, pass that to the callee, and replace the original
4189 * boxed object in the arg array with the copy.
4191 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4192 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4193 mono_array_setref (params, i, copy);
4196 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4199 case MONO_TYPE_STRING:
4200 case MONO_TYPE_OBJECT:
4201 case MONO_TYPE_CLASS:
4202 case MONO_TYPE_ARRAY:
4203 case MONO_TYPE_SZARRAY:
4205 pa [i] = mono_array_addr (params, MonoObject*, i);
4206 // FIXME: I need to check this code path
4208 pa [i] = mono_array_get (params, MonoObject*, i);
4210 case MONO_TYPE_GENERICINST:
4212 t = &t->data.generic_class->container_class->this_arg;
4214 t = &t->data.generic_class->container_class->byval_arg;
4216 case MONO_TYPE_PTR: {
4219 /* The argument should be an IntPtr */
4220 arg = mono_array_get (params, MonoObject*, i);
4224 g_assert (arg->vtable->klass == mono_defaults.int_class);
4225 pa [i] = ((MonoIntPtr*)arg)->m_value;
4230 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4235 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4238 if (mono_class_is_nullable (method->klass)) {
4239 /* Need to create a boxed vtype instead */
4245 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4249 obj = mono_object_new (mono_domain_get (), method->klass);
4250 g_assert (obj); /*maybe we should raise a TLE instead?*/
4251 #ifndef DISABLE_REMOTING
4252 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4253 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4256 if (method->klass->valuetype)
4257 o = mono_object_unbox (obj);
4260 } else if (method->klass->valuetype) {
4261 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4264 mono_runtime_invoke (method, o, pa, exc);
4267 if (mono_class_is_nullable (method->klass)) {
4268 MonoObject *nullable;
4270 /* Convert the unboxed vtype into a Nullable structure */
4271 nullable = mono_object_new (mono_domain_get (), method->klass);
4273 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4274 obj = mono_object_unbox (nullable);
4277 /* obj must be already unboxed if needed */
4278 res = mono_runtime_invoke (method, obj, pa, exc);
4280 if (sig->ret->type == MONO_TYPE_PTR) {
4281 MonoClass *pointer_class;
4282 static MonoMethod *box_method;
4284 MonoObject *box_exc;
4287 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4288 * convert it to a Pointer object.
4290 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4292 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4294 g_assert (res->vtable->klass == mono_defaults.int_class);
4295 box_args [0] = ((MonoIntPtr*)res)->m_value;
4296 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4297 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4298 g_assert (!box_exc);
4301 if (has_byref_nullables) {
4303 * The runtime invoke wrapper already converted byref nullables back,
4304 * and stored them in pa, we just need to copy them back to the
4307 for (i = 0; i < mono_array_length (params); i++) {
4308 MonoType *t = sig->params [i];
4310 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4311 mono_array_setref (params, i, pa [i]);
4320 arith_overflow (void)
4322 mono_raise_exception (mono_get_exception_overflow ());
4326 * mono_object_allocate:
4327 * @size: number of bytes to allocate
4329 * This is a very simplistic routine until we have our GC-aware
4332 * Returns: an allocated object of size @size, or NULL on failure.
4334 static inline void *
4335 mono_object_allocate (size_t size, MonoVTable *vtable)
4338 mono_stats.new_object_count++;
4339 ALLOC_OBJECT (o, vtable, size);
4345 * mono_object_allocate_ptrfree:
4346 * @size: number of bytes to allocate
4348 * Note that the memory allocated is not zeroed.
4349 * Returns: an allocated object of size @size, or NULL on failure.
4351 static inline void *
4352 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4355 mono_stats.new_object_count++;
4356 ALLOC_PTRFREE (o, vtable, size);
4360 static inline void *
4361 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4364 ALLOC_TYPED (o, size, vtable);
4365 mono_stats.new_object_count++;
4372 * @klass: the class of the object that we want to create
4374 * Returns: a newly created object whose definition is
4375 * looked up using @klass. This will not invoke any constructors,
4376 * so the consumer of this routine has to invoke any constructors on
4377 * its own to initialize the object.
4379 * It returns NULL on failure.
4382 mono_object_new (MonoDomain *domain, MonoClass *klass)
4386 MONO_ARCH_SAVE_REGS;
4387 vtable = mono_class_vtable (domain, klass);
4390 return mono_object_new_specific (vtable);
4394 * mono_object_new_pinned:
4396 * Same as mono_object_new, but the returned object will be pinned.
4397 * For SGEN, these objects will only be freed at appdomain unload.
4400 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4404 MONO_ARCH_SAVE_REGS;
4405 vtable = mono_class_vtable (domain, klass);
4410 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4412 return mono_object_new_specific (vtable);
4417 * mono_object_new_specific:
4418 * @vtable: the vtable of the object that we want to create
4420 * Returns: A newly created object with class and domain specified
4424 mono_object_new_specific (MonoVTable *vtable)
4428 MONO_ARCH_SAVE_REGS;
4430 /* check for is_com_object for COM Interop */
4431 if (vtable->remote || vtable->klass->is_com_object)
4434 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4437 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4440 mono_class_init (klass);
4442 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4444 vtable->domain->create_proxy_for_type_method = im;
4447 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4449 o = mono_runtime_invoke (im, NULL, pa, NULL);
4450 if (o != NULL) return o;
4453 return mono_object_new_alloc_specific (vtable);
4457 mono_object_new_alloc_specific (MonoVTable *vtable)
4461 if (!vtable->klass->has_references) {
4462 o = mono_object_new_ptrfree (vtable);
4463 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4464 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4466 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4467 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4469 if (G_UNLIKELY (vtable->klass->has_finalize))
4470 mono_object_register_finalizer (o);
4472 if (G_UNLIKELY (profile_allocs))
4473 mono_profiler_allocation (o, vtable->klass);
4478 mono_object_new_fast (MonoVTable *vtable)
4481 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4486 mono_object_new_ptrfree (MonoVTable *vtable)
4489 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4490 #if NEED_TO_ZERO_PTRFREE
4491 /* an inline memset is much faster for the common vcase of small objects
4492 * note we assume the allocated size is a multiple of sizeof (void*).
4494 if (vtable->klass->instance_size < 128) {
4496 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4497 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4503 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4510 mono_object_new_ptrfree_box (MonoVTable *vtable)
4513 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4514 /* the object will be boxed right away, no need to memzero it */
4519 * mono_class_get_allocation_ftn:
4521 * @for_box: the object will be used for boxing
4522 * @pass_size_in_words:
4524 * Return the allocation function appropriate for the given class.
4528 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4530 *pass_size_in_words = FALSE;
4532 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4533 profile_allocs = FALSE;
4535 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4536 return mono_object_new_specific;
4538 if (!vtable->klass->has_references) {
4539 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4541 return mono_object_new_ptrfree_box;
4542 return mono_object_new_ptrfree;
4545 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4547 return mono_object_new_fast;
4550 * FIXME: This is actually slower than mono_object_new_fast, because
4551 * of the overhead of parameter passing.
4554 *pass_size_in_words = TRUE;
4555 #ifdef GC_REDIRECT_TO_LOCAL
4556 return GC_local_gcj_fast_malloc;
4558 return GC_gcj_fast_malloc;
4563 return mono_object_new_specific;
4567 * mono_object_new_from_token:
4568 * @image: Context where the type_token is hosted
4569 * @token: a token of the type that we want to create
4571 * Returns: A newly created object whose definition is
4572 * looked up using @token in the @image image
4575 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4579 class = mono_class_get (image, token);
4581 return mono_object_new (domain, class);
4586 * mono_object_clone:
4587 * @obj: the object to clone
4589 * Returns: A newly created object who is a shallow copy of @obj
4592 mono_object_clone (MonoObject *obj)
4595 int size = obj->vtable->klass->instance_size;
4597 if (obj->vtable->klass->rank)
4598 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4600 o = mono_object_allocate (size, obj->vtable);
4602 if (obj->vtable->klass->has_references) {
4603 mono_gc_wbarrier_object_copy (o, obj);
4605 int size = obj->vtable->klass->instance_size;
4606 /* do not copy the sync state */
4607 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4609 if (G_UNLIKELY (profile_allocs))
4610 mono_profiler_allocation (o, obj->vtable->klass);
4612 if (obj->vtable->klass->has_finalize)
4613 mono_object_register_finalizer (o);
4618 * mono_array_full_copy:
4619 * @src: source array to copy
4620 * @dest: destination array
4622 * Copies the content of one array to another with exactly the same type and size.
4625 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4628 MonoClass *klass = src->obj.vtable->klass;
4630 MONO_ARCH_SAVE_REGS;
4632 g_assert (klass == dest->obj.vtable->klass);
4634 size = mono_array_length (src);
4635 g_assert (size == mono_array_length (dest));
4636 size *= mono_array_element_size (klass);
4638 if (klass->element_class->valuetype) {
4639 if (klass->element_class->has_references)
4640 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4642 mono_gc_memmove (&dest->vector, &src->vector, size);
4644 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4647 mono_gc_memmove (&dest->vector, &src->vector, size);
4652 * mono_array_clone_in_domain:
4653 * @domain: the domain in which the array will be cloned into
4654 * @array: the array to clone
4656 * This routine returns a copy of the array that is hosted on the
4657 * specified MonoDomain.
4660 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4665 MonoClass *klass = array->obj.vtable->klass;
4667 MONO_ARCH_SAVE_REGS;
4669 if (array->bounds == NULL) {
4670 size = mono_array_length (array);
4671 o = mono_array_new_full (domain, klass, &size, NULL);
4673 size *= mono_array_element_size (klass);
4675 if (klass->element_class->valuetype) {
4676 if (klass->element_class->has_references)
4677 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4679 mono_gc_memmove (&o->vector, &array->vector, size);
4681 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4684 mono_gc_memmove (&o->vector, &array->vector, size);
4689 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4690 size = mono_array_element_size (klass);
4691 for (i = 0; i < klass->rank; ++i) {
4692 sizes [i] = array->bounds [i].length;
4693 size *= array->bounds [i].length;
4694 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4696 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4698 if (klass->element_class->valuetype) {
4699 if (klass->element_class->has_references)
4700 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4702 mono_gc_memmove (&o->vector, &array->vector, size);
4704 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4707 mono_gc_memmove (&o->vector, &array->vector, size);
4715 * @array: the array to clone
4717 * Returns: A newly created array who is a shallow copy of @array
4720 mono_array_clone (MonoArray *array)
4722 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4725 /* helper macros to check for overflow when calculating the size of arrays */
4726 #ifdef MONO_BIG_ARRAYS
4727 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4728 #define MYGUINT_MAX MYGUINT64_MAX
4729 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4730 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4731 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4732 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4733 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4735 #define MYGUINT32_MAX 4294967295U
4736 #define MYGUINT_MAX MYGUINT32_MAX
4737 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4738 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4739 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4740 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4741 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4745 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4749 byte_len = mono_array_element_size (class);
4750 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4753 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4755 byte_len += sizeof (MonoArray);
4763 * mono_array_new_full:
4764 * @domain: domain where the object is created
4765 * @array_class: array class
4766 * @lengths: lengths for each dimension in the array
4767 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4769 * This routine creates a new array objects with the given dimensions,
4770 * lower bounds and type.
4773 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4775 uintptr_t byte_len, len, bounds_size;
4778 MonoArrayBounds *bounds;
4782 if (!array_class->inited)
4783 mono_class_init (array_class);
4787 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4788 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4790 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4794 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4796 for (i = 0; i < array_class->rank; ++i) {
4797 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4799 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4800 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4805 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4806 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4810 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4811 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4812 byte_len = (byte_len + 3) & ~3;
4813 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4814 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4815 byte_len += bounds_size;
4818 * Following three lines almost taken from mono_object_new ():
4819 * they need to be kept in sync.
4821 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4822 #ifndef HAVE_SGEN_GC
4823 if (!array_class->has_references) {
4824 o = mono_object_allocate_ptrfree (byte_len, vtable);
4825 #if NEED_TO_ZERO_PTRFREE
4826 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4828 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4829 o = mono_object_allocate_spec (byte_len, vtable);
4831 o = mono_object_allocate (byte_len, vtable);
4834 array = (MonoArray*)o;
4835 array->max_length = len;
4838 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4839 array->bounds = bounds;
4843 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4845 o = mono_gc_alloc_vector (vtable, byte_len, len);
4846 array = (MonoArray*)o;
4847 mono_stats.new_object_count++;
4849 bounds = array->bounds;
4853 for (i = 0; i < array_class->rank; ++i) {
4854 bounds [i].length = lengths [i];
4856 bounds [i].lower_bound = lower_bounds [i];
4860 if (G_UNLIKELY (profile_allocs))
4861 mono_profiler_allocation (o, array_class);
4868 * @domain: domain where the object is created
4869 * @eclass: element class
4870 * @n: number of array elements
4872 * This routine creates a new szarray with @n elements of type @eclass.
4875 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4879 MONO_ARCH_SAVE_REGS;
4881 ac = mono_array_class_get (eclass, 1);
4884 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4888 * mono_array_new_specific:
4889 * @vtable: a vtable in the appropriate domain for an initialized class
4890 * @n: number of array elements
4892 * This routine is a fast alternative to mono_array_new() for code which
4893 * can be sure about the domain it operates in.
4896 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4902 MONO_ARCH_SAVE_REGS;
4904 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4909 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4910 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4913 #ifndef HAVE_SGEN_GC
4914 if (!vtable->klass->has_references) {
4915 o = mono_object_allocate_ptrfree (byte_len, vtable);
4916 #if NEED_TO_ZERO_PTRFREE
4917 ((MonoArray*)o)->bounds = NULL;
4918 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4920 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4921 o = mono_object_allocate_spec (byte_len, vtable);
4923 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4924 o = mono_object_allocate (byte_len, vtable);
4927 ao = (MonoArray *)o;
4930 o = mono_gc_alloc_vector (vtable, byte_len, n);
4932 mono_stats.new_object_count++;
4935 if (G_UNLIKELY (profile_allocs))
4936 mono_profiler_allocation (o, vtable->klass);
4942 * mono_string_new_utf16:
4943 * @text: a pointer to an utf16 string
4944 * @len: the length of the string
4946 * Returns: A newly created string object which contains @text.
4949 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4953 s = mono_string_new_size (domain, len);
4954 g_assert (s != NULL);
4956 memcpy (mono_string_chars (s), text, len * 2);
4962 * mono_string_new_size:
4963 * @text: a pointer to an utf16 string
4964 * @len: the length of the string
4966 * Returns: A newly created string object of @len
4969 mono_string_new_size (MonoDomain *domain, gint32 len)
4973 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4975 /* overflow ? can't fit it, can't allocate it! */
4977 mono_gc_out_of_memory (-1);
4979 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4982 #ifndef HAVE_SGEN_GC
4983 s = mono_object_allocate_ptrfree (size, vtable);
4987 s = mono_gc_alloc_string (vtable, size, len);
4989 #if NEED_TO_ZERO_PTRFREE
4992 if (G_UNLIKELY (profile_allocs))
4993 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4999 * mono_string_new_len:
5000 * @text: a pointer to an utf8 string
5001 * @length: number of bytes in @text to consider
5003 * Returns: A newly created string object which contains @text.
5006 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5008 GError *error = NULL;
5009 MonoString *o = NULL;
5011 glong items_written;
5013 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5016 o = mono_string_new_utf16 (domain, ut, items_written);
5018 g_error_free (error);
5027 * @text: a pointer to an utf8 string
5029 * Returns: A newly created string object which contains @text.
5032 mono_string_new (MonoDomain *domain, const char *text)
5034 GError *error = NULL;
5035 MonoString *o = NULL;
5037 glong items_written;
5042 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5045 o = mono_string_new_utf16 (domain, ut, items_written);
5047 g_error_free (error);
5050 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5055 MonoString *o = NULL;
5057 if (!g_utf8_validate (text, -1, &end))
5060 len = g_utf8_strlen (text, -1);
5061 o = mono_string_new_size (domain, len);
5062 str = mono_string_chars (o);
5064 while (text < end) {
5065 *str++ = g_utf8_get_char (text);
5066 text = g_utf8_next_char (text);
5073 * mono_string_new_wrapper:
5074 * @text: pointer to utf8 characters.
5076 * Helper function to create a string object from @text in the current domain.
5079 mono_string_new_wrapper (const char *text)
5081 MonoDomain *domain = mono_domain_get ();
5083 MONO_ARCH_SAVE_REGS;
5086 return mono_string_new (domain, text);
5093 * @class: the class of the value
5094 * @value: a pointer to the unboxed data
5096 * Returns: A newly created object which contains @value.
5099 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5105 g_assert (class->valuetype);
5106 if (mono_class_is_nullable (class))
5107 return mono_nullable_box (value, class);
5109 vtable = mono_class_vtable (domain, class);
5112 size = mono_class_instance_size (class);
5113 res = mono_object_new_alloc_specific (vtable);
5114 if (G_UNLIKELY (profile_allocs))
5115 mono_profiler_allocation (res, class);
5117 size = size - sizeof (MonoObject);
5120 g_assert (size == mono_class_value_size (class, NULL));
5121 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5123 #if NO_UNALIGNED_ACCESS
5124 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5128 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5131 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5134 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5137 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5140 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5144 if (class->has_finalize)
5145 mono_object_register_finalizer (res);
5151 * @dest: destination pointer
5152 * @src: source pointer
5153 * @klass: a valuetype class
5155 * Copy a valuetype from @src to @dest. This function must be used
5156 * when @klass contains references fields.
5159 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5161 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5165 * mono_value_copy_array:
5166 * @dest: destination array
5167 * @dest_idx: index in the @dest array
5168 * @src: source pointer
5169 * @count: number of items
5171 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5172 * This function must be used when @klass contains references fields.
5173 * Overlap is handled.
5176 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5178 int size = mono_array_element_size (dest->obj.vtable->klass);
5179 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5180 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5181 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5185 * mono_object_get_domain:
5186 * @obj: object to query
5188 * Returns: the MonoDomain where the object is hosted
5191 mono_object_get_domain (MonoObject *obj)
5193 return mono_object_domain (obj);
5197 * mono_object_get_class:
5198 * @obj: object to query
5200 * Returns: the MonOClass of the object.
5203 mono_object_get_class (MonoObject *obj)
5205 return mono_object_class (obj);
5208 * mono_object_get_size:
5209 * @o: object to query
5211 * Returns: the size, in bytes, of @o
5214 mono_object_get_size (MonoObject* o)
5216 MonoClass* klass = mono_object_class (o);
5217 if (klass == mono_defaults.string_class) {
5218 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5219 } else if (o->vtable->rank) {
5220 MonoArray *array = (MonoArray*)o;
5221 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5222 if (array->bounds) {
5225 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5229 return mono_class_instance_size (klass);
5234 * mono_object_unbox:
5235 * @obj: object to unbox
5237 * Returns: a pointer to the start of the valuetype boxed in this
5240 * This method will assert if the object passed is not a valuetype.
5243 mono_object_unbox (MonoObject *obj)
5245 /* add assert for valuetypes? */
5246 g_assert (obj->vtable->klass->valuetype);
5247 return ((char*)obj) + sizeof (MonoObject);
5251 * mono_object_isinst:
5253 * @klass: a pointer to a class
5255 * Returns: @obj if @obj is derived from @klass
5258 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5261 mono_class_init (klass);
5263 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5264 return mono_object_isinst_mbyref (obj, klass);
5269 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5273 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5282 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5283 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5287 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5288 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5291 MonoClass *oklass = vt->klass;
5292 if (mono_class_is_transparent_proxy (oklass))
5293 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5295 mono_class_setup_supertypes (klass);
5296 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5299 #ifndef DISABLE_REMOTING
5300 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5302 MonoDomain *domain = mono_domain_get ();
5304 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5305 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5306 MonoMethod *im = NULL;
5309 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5310 im = mono_object_get_virtual_method (rp, im);
5313 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5316 res = mono_runtime_invoke (im, rp, pa, NULL);
5318 if (*(MonoBoolean *) mono_object_unbox(res)) {
5319 /* Update the vtable of the remote type, so it can safely cast to this new type */
5320 mono_upgrade_remote_class (domain, obj, klass);
5324 #endif /* DISABLE_REMOTING */
5329 * mono_object_castclass_mbyref:
5331 * @klass: a pointer to a class
5333 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5336 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5338 if (!obj) return NULL;
5339 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5341 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5343 "InvalidCastException"));
5348 MonoDomain *orig_domain;
5354 str_lookup (MonoDomain *domain, gpointer user_data)
5356 LDStrInfo *info = user_data;
5357 if (info->res || domain == info->orig_domain)
5359 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5365 mono_string_get_pinned (MonoString *str)
5369 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5370 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5372 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5373 news->length = mono_string_length (str);
5379 #define mono_string_get_pinned(str) (str)
5383 mono_string_is_interned_lookup (MonoString *str, int insert)
5385 MonoGHashTable *ldstr_table;
5389 domain = ((MonoObject *)str)->vtable->domain;
5390 ldstr_table = domain->ldstr_table;
5392 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5397 str = mono_string_get_pinned (str);
5399 mono_g_hash_table_insert (ldstr_table, str, str);
5403 LDStrInfo ldstr_info;
5404 ldstr_info.orig_domain = domain;
5405 ldstr_info.ins = str;
5406 ldstr_info.res = NULL;
5408 mono_domain_foreach (str_lookup, &ldstr_info);
5409 if (ldstr_info.res) {
5411 * the string was already interned in some other domain:
5412 * intern it in the current one as well.
5414 mono_g_hash_table_insert (ldstr_table, str, str);
5424 * mono_string_is_interned:
5425 * @o: String to probe
5427 * Returns whether the string has been interned.
5430 mono_string_is_interned (MonoString *o)
5432 return mono_string_is_interned_lookup (o, FALSE);
5436 * mono_string_intern:
5437 * @o: String to intern
5439 * Interns the string passed.
5440 * Returns: The interned string.
5443 mono_string_intern (MonoString *str)
5445 return mono_string_is_interned_lookup (str, TRUE);
5450 * @domain: the domain where the string will be used.
5451 * @image: a metadata context
5452 * @idx: index into the user string table.
5454 * Implementation for the ldstr opcode.
5455 * Returns: a loaded string from the @image/@idx combination.
5458 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5460 MONO_ARCH_SAVE_REGS;
5462 if (image->dynamic) {
5463 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5466 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5467 return NULL; /*FIXME we should probably be raising an exception here*/
5468 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5473 * mono_ldstr_metadata_sig
5474 * @domain: the domain for the string
5475 * @sig: the signature of a metadata string
5477 * Returns: a MonoString for a string stored in the metadata
5480 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5482 const char *str = sig;
5483 MonoString *o, *interned;
5486 len2 = mono_metadata_decode_blob_size (str, &str);
5489 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5490 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5493 guint16 *p2 = (guint16*)mono_string_chars (o);
5494 for (i = 0; i < len2; ++i) {
5495 *p2 = GUINT16_FROM_LE (*p2);
5501 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5503 /* o will get garbage collected */
5507 o = mono_string_get_pinned (o);
5509 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5516 * mono_string_to_utf8:
5517 * @s: a System.String
5519 * Returns the UTF8 representation for @s.
5520 * The resulting buffer needs to be freed with mono_free().
5522 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5525 mono_string_to_utf8 (MonoString *s)
5528 char *result = mono_string_to_utf8_checked (s, &error);
5530 if (!mono_error_ok (&error))
5531 mono_error_raise_exception (&error);
5536 * mono_string_to_utf8_checked:
5537 * @s: a System.String
5538 * @error: a MonoError.
5540 * Converts a MonoString to its UTF8 representation. May fail; check
5541 * @error to determine whether the conversion was successful.
5542 * The resulting buffer should be freed with mono_free().
5545 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5549 GError *gerror = NULL;
5551 mono_error_init (error);
5557 return g_strdup ("");
5559 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5561 mono_error_set_argument (error, "string", "%s", gerror->message);
5562 g_error_free (gerror);
5565 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5566 if (s->length > written) {
5567 /* allocate the total length and copy the part of the string that has been converted */
5568 char *as2 = g_malloc0 (s->length);
5569 memcpy (as2, as, written);
5578 * mono_string_to_utf8_ignore:
5581 * Converts a MonoString to its UTF8 representation. Will ignore
5582 * invalid surrogate pairs.
5583 * The resulting buffer should be freed with mono_free().
5587 mono_string_to_utf8_ignore (MonoString *s)
5596 return g_strdup ("");
5598 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5600 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5601 if (s->length > written) {
5602 /* allocate the total length and copy the part of the string that has been converted */
5603 char *as2 = g_malloc0 (s->length);
5604 memcpy (as2, as, written);
5613 * mono_string_to_utf8_image_ignore:
5614 * @s: a System.String
5616 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5619 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5621 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5625 * mono_string_to_utf8_mp_ignore:
5626 * @s: a System.String
5628 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5631 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5633 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5638 * mono_string_to_utf16:
5641 * Return an null-terminated array of the utf-16 chars
5642 * contained in @s. The result must be freed with g_free().
5643 * This is a temporary helper until our string implementation
5644 * is reworked to always include the null terminating char.
5647 mono_string_to_utf16 (MonoString *s)
5654 as = g_malloc ((s->length * 2) + 2);
5655 as [(s->length * 2)] = '\0';
5656 as [(s->length * 2) + 1] = '\0';
5659 return (gunichar2 *)(as);
5662 memcpy (as, mono_string_chars(s), s->length * 2);
5663 return (gunichar2 *)(as);
5667 * mono_string_from_utf16:
5668 * @data: the UTF16 string (LPWSTR) to convert
5670 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5672 * Returns: a MonoString.
5675 mono_string_from_utf16 (gunichar2 *data)
5677 MonoDomain *domain = mono_domain_get ();
5683 while (data [len]) len++;
5685 return mono_string_new_utf16 (domain, data, len);
5690 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5697 r = mono_string_to_utf8_ignore (s);
5699 r = mono_string_to_utf8_checked (s, error);
5700 if (!mono_error_ok (error))
5707 len = strlen (r) + 1;
5709 mp_s = mono_mempool_alloc (mp, len);
5711 mp_s = mono_image_alloc (image, len);
5713 memcpy (mp_s, r, len);
5721 * mono_string_to_utf8_image:
5722 * @s: a System.String
5724 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5727 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5729 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5733 * mono_string_to_utf8_mp:
5734 * @s: a System.String
5736 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5739 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5741 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5745 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5748 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5750 eh_callbacks = *cbs;
5753 MonoRuntimeExceptionHandlingCallbacks *
5754 mono_get_eh_callbacks (void)
5756 return &eh_callbacks;
5760 * mono_raise_exception:
5761 * @ex: exception object
5763 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5766 mono_raise_exception (MonoException *ex)
5769 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5770 * that will cause gcc to omit the function epilog, causing problems when
5771 * the JIT tries to walk the stack, since the return address on the stack
5772 * will point into the next function in the executable, not this one.
5774 eh_callbacks.mono_raise_exception (ex);
5778 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5780 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5784 * mono_wait_handle_new:
5785 * @domain: Domain where the object will be created
5786 * @handle: Handle for the wait handle
5788 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5791 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5793 MonoWaitHandle *res;
5794 gpointer params [1];
5795 static MonoMethod *handle_set;
5797 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5799 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5801 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5803 params [0] = &handle;
5804 mono_runtime_invoke (handle_set, res, params, NULL);
5810 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5812 static MonoClassField *f_os_handle;
5813 static MonoClassField *f_safe_handle;
5815 if (!f_os_handle && !f_safe_handle) {
5816 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5817 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5822 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5826 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5833 mono_runtime_capture_context (MonoDomain *domain)
5835 RuntimeInvokeFunction runtime_invoke;
5837 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5838 MonoMethod *method = mono_get_context_capture_method ();
5839 MonoMethod *wrapper;
5842 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5843 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5844 domain->capture_context_method = mono_compile_method (method);
5847 runtime_invoke = domain->capture_context_runtime_invoke;
5849 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5852 * mono_async_result_new:
5853 * @domain:domain where the object will be created.
5854 * @handle: wait handle.
5855 * @state: state to pass to AsyncResult
5856 * @data: C closure data.
5858 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5859 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5863 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5865 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5866 MonoObject *context = mono_runtime_capture_context (domain);
5867 /* we must capture the execution context from the original thread */
5869 MONO_OBJECT_SETREF (res, execution_context, context);
5870 /* note: result may be null if the flow is suppressed */
5874 MONO_OBJECT_SETREF (res, object_data, object_data);
5875 MONO_OBJECT_SETREF (res, async_state, state);
5877 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5879 res->sync_completed = FALSE;
5880 res->completed = FALSE;
5886 mono_message_init (MonoDomain *domain,
5887 MonoMethodMessage *this,
5888 MonoReflectionMethod *method,
5889 MonoArray *out_args)
5891 static MonoClass *object_array_klass;
5892 static MonoClass *byte_array_klass;
5893 static MonoClass *string_array_klass;
5894 MonoMethodSignature *sig = mono_method_signature (method->method);
5900 if (!object_array_klass) {
5903 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5905 byte_array_klass = klass;
5907 klass = mono_array_class_get (mono_defaults.string_class, 1);
5909 string_array_klass = klass;
5911 klass = mono_array_class_get (mono_defaults.object_class, 1);
5914 mono_atomic_store_release (&object_array_klass, klass);
5917 MONO_OBJECT_SETREF (this, method, method);
5919 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5920 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5921 this->async_result = NULL;
5922 this->call_type = CallType_Sync;
5924 names = g_new (char *, sig->param_count);
5925 mono_method_get_param_names (method->method, (const char **) names);
5926 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5928 for (i = 0; i < sig->param_count; i++) {
5929 name = mono_string_new (domain, names [i]);
5930 mono_array_setref (this->names, i, name);
5934 for (i = 0, j = 0; i < sig->param_count; i++) {
5935 if (sig->params [i]->byref) {
5937 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5938 mono_array_setref (this->args, i, arg);
5942 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5946 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5949 mono_array_set (this->arg_types, guint8, i, arg_type);
5953 #ifndef DISABLE_REMOTING
5955 * mono_remoting_invoke:
5956 * @real_proxy: pointer to a RealProxy object
5957 * @msg: The MonoMethodMessage to execute
5958 * @exc: used to store exceptions
5959 * @out_args: used to store output arguments
5961 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5962 * IMessage interface and it is not trivial to extract results from there. So
5963 * we call an helper method PrivateInvoke instead of calling
5964 * RealProxy::Invoke() directly.
5966 * Returns: the result object.
5969 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5970 MonoObject **exc, MonoArray **out_args)
5972 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5975 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5978 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5980 real_proxy->vtable->domain->private_invoke_method = im;
5983 pa [0] = real_proxy;
5988 return mono_runtime_invoke (im, NULL, pa, exc);
5993 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5994 MonoObject **exc, MonoArray **out_args)
5996 static MonoClass *object_array_klass;
5999 MonoMethodSignature *sig;
6001 int i, j, outarg_count = 0;
6003 #ifndef DISABLE_REMOTING
6004 if (target && mono_object_is_transparent_proxy (target)) {
6005 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6006 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6007 target = tp->rp->unwrapped_server;
6009 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6014 domain = mono_domain_get ();
6015 method = msg->method->method;
6016 sig = mono_method_signature (method);
6018 for (i = 0; i < sig->param_count; i++) {
6019 if (sig->params [i]->byref)
6023 if (!object_array_klass) {
6026 klass = mono_array_class_get (mono_defaults.object_class, 1);
6029 mono_memory_barrier ();
6030 object_array_klass = klass;
6033 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6034 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6037 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6039 for (i = 0, j = 0; i < sig->param_count; i++) {
6040 if (sig->params [i]->byref) {
6042 arg = mono_array_get (msg->args, gpointer, i);
6043 mono_array_setref (*out_args, j, arg);
6052 * mono_object_to_string:
6054 * @exc: Any exception thrown by ToString (). May be NULL.
6056 * Returns: the result of calling ToString () on an object.
6059 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6061 static MonoMethod *to_string = NULL;
6067 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6069 method = mono_object_get_virtual_method (obj, to_string);
6071 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
6075 * mono_print_unhandled_exception:
6076 * @exc: The exception
6078 * Prints the unhandled exception.
6081 mono_print_unhandled_exception (MonoObject *exc)
6084 char *message = (char*)"";
6085 gboolean free_message = FALSE;
6088 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6089 message = g_strdup ("OutOfMemoryException");
6090 free_message = TRUE;
6093 if (((MonoException*)exc)->native_trace_ips) {
6094 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6095 free_message = TRUE;
6097 MonoObject *other_exc = NULL;
6098 str = mono_object_to_string (exc, &other_exc);
6100 message = g_strdup ("Nested exception, bailing out");
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 = ji->method;
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;