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 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2118 /* class_vtable_array keeps an array of created vtables
2120 g_ptr_array_add (domain->class_vtable_array, vt);
2121 /* class->runtime_info is protected by the loader lock, both when
2122 * it it enlarged and when it is stored info.
2126 * Store the vtable in class->runtime_info.
2127 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2129 mono_memory_barrier ();
2131 old_info = class->runtime_info;
2132 if (old_info && old_info->max_domain >= domain->domain_id) {
2133 /* someone already created a large enough runtime info */
2134 old_info->domain_vtables [domain->domain_id] = vt;
2136 int new_size = domain->domain_id;
2138 new_size = MAX (new_size, old_info->max_domain);
2140 /* make the new size a power of two */
2142 while (new_size > i)
2145 /* this is a bounded memory retention issue: may want to
2146 * handle it differently when we'll have a rcu-like system.
2148 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2149 runtime_info->max_domain = new_size - 1;
2150 /* copy the stuff from the older info */
2152 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2154 runtime_info->domain_vtables [domain->domain_id] = vt;
2156 mono_memory_barrier ();
2157 class->runtime_info = runtime_info;
2160 if (class == mono_defaults.monotype_class) {
2161 /*FIXME check for OOM*/
2162 vt->type = mono_type_get_object (domain, &class->byval_arg);
2163 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2164 /* This is unregistered in
2165 unregister_vtable_reflection_type() in
2167 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2170 mono_domain_unlock (domain);
2171 mono_loader_unlock ();
2173 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2174 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2175 mono_raise_exception (mono_class_get_exception_for_failure (class));
2177 /* make sure the parent is initialized */
2178 /*FIXME shouldn't this fail the current type?*/
2180 mono_class_vtable_full (domain, class->parent, raise_on_error);
2185 #ifndef DISABLE_REMOTING
2187 * mono_class_proxy_vtable:
2188 * @domain: the application domain
2189 * @remove_class: the remote class
2191 * Creates a vtable for transparent proxies. It is basically
2192 * a copy of the real vtable of the class wrapped in @remote_class,
2193 * but all function pointers invoke the remoting functions, and
2194 * vtable->klass points to the transparent proxy class, and not to @class.
2197 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2200 MonoVTable *vt, *pvt;
2201 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2203 GSList *extra_interfaces = NULL;
2204 MonoClass *class = remote_class->proxy_class;
2205 gpointer *interface_offsets;
2209 #ifdef COMPRESSED_INTERFACE_BITMAP
2213 vt = mono_class_vtable (domain, class);
2214 g_assert (vt); /*FIXME property handle failure*/
2215 max_interface_id = vt->max_interface_id;
2217 /* Calculate vtable space for extra interfaces */
2218 for (j = 0; j < remote_class->interface_count; j++) {
2219 MonoClass* iclass = remote_class->interfaces[j];
2223 /*FIXME test for interfaces with variant generic arguments*/
2224 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2225 continue; /* interface implemented by the class */
2226 if (g_slist_find (extra_interfaces, iclass))
2229 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2231 method_count = mono_class_num_methods (iclass);
2233 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2234 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2236 for (i = 0; i < ifaces->len; ++i) {
2237 MonoClass *ic = g_ptr_array_index (ifaces, i);
2238 /*FIXME test for interfaces with variant generic arguments*/
2239 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2240 continue; /* interface implemented by the class */
2241 if (g_slist_find (extra_interfaces, ic))
2243 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2244 method_count += mono_class_num_methods (ic);
2246 g_ptr_array_free (ifaces, TRUE);
2249 extra_interface_vtsize += method_count * sizeof (gpointer);
2250 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2254 mono_stats.imt_number_of_tables++;
2255 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2256 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2257 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2259 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2260 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2263 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2265 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2267 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2269 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2270 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2272 pvt->klass = mono_defaults.transparent_proxy_class;
2273 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2274 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2276 /* initialize vtable */
2277 mono_class_setup_vtable (class);
2278 for (i = 0; i < class->vtable_size; ++i) {
2281 if ((cm = class->vtable [i]))
2282 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2284 pvt->vtable [i] = NULL;
2287 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2288 /* create trampolines for abstract methods */
2289 for (k = class; k; k = k->parent) {
2291 gpointer iter = NULL;
2292 while ((m = mono_class_get_methods (k, &iter)))
2293 if (!pvt->vtable [m->slot])
2294 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2298 pvt->max_interface_id = max_interface_id;
2299 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2300 #ifdef COMPRESSED_INTERFACE_BITMAP
2301 bitmap = g_malloc0 (bsize);
2303 bitmap = mono_domain_alloc0 (domain, bsize);
2306 if (! ARCH_USE_IMT) {
2307 /* initialize interface offsets */
2308 for (i = 0; i < class->interface_offsets_count; ++i) {
2309 int interface_id = class->interfaces_packed [i]->interface_id;
2310 int slot = class->interface_offsets_packed [i];
2311 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2314 for (i = 0; i < class->interface_offsets_count; ++i) {
2315 int interface_id = class->interfaces_packed [i]->interface_id;
2316 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2319 if (extra_interfaces) {
2320 int slot = class->vtable_size;
2326 /* Create trampolines for the methods of the interfaces */
2327 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2328 interf = list_item->data;
2330 if (! ARCH_USE_IMT) {
2331 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2333 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2337 while ((cm = mono_class_get_methods (interf, &iter)))
2338 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2340 slot += mono_class_num_methods (interf);
2342 if (! ARCH_USE_IMT) {
2343 g_slist_free (extra_interfaces);
2348 /* Now that the vtable is full, we can actually fill up the IMT */
2349 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2350 if (extra_interfaces) {
2351 g_slist_free (extra_interfaces);
2355 #ifdef COMPRESSED_INTERFACE_BITMAP
2356 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2357 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2358 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2361 pvt->interface_bitmap = bitmap;
2366 #endif /* DISABLE_REMOTING */
2369 * mono_class_field_is_special_static:
2371 * Returns whether @field is a thread/context static field.
2374 mono_class_field_is_special_static (MonoClassField *field)
2376 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2378 if (mono_field_is_deleted (field))
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2381 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2388 * mono_class_field_get_special_static_type:
2389 * @field: The MonoClassField describing the field.
2391 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2392 * SPECIAL_STATIC_NONE otherwise.
2395 mono_class_field_get_special_static_type (MonoClassField *field)
2397 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2398 return SPECIAL_STATIC_NONE;
2399 if (mono_field_is_deleted (field))
2400 return SPECIAL_STATIC_NONE;
2401 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2402 return field_is_special_static (field->parent, field);
2403 return SPECIAL_STATIC_NONE;
2407 * mono_class_has_special_static_fields:
2409 * Returns whenever @klass has any thread/context static fields.
2412 mono_class_has_special_static_fields (MonoClass *klass)
2414 MonoClassField *field;
2418 while ((field = mono_class_get_fields (klass, &iter))) {
2419 g_assert (field->parent == klass);
2420 if (mono_class_field_is_special_static (field))
2427 #ifndef DISABLE_REMOTING
2429 * create_remote_class_key:
2430 * Creates an array of pointers that can be used as a hash key for a remote class.
2431 * The first element of the array is the number of pointers.
2434 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2439 if (remote_class == NULL) {
2440 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2441 key = g_malloc (sizeof(gpointer) * 3);
2442 key [0] = GINT_TO_POINTER (2);
2443 key [1] = mono_defaults.marshalbyrefobject_class;
2444 key [2] = extra_class;
2446 key = g_malloc (sizeof(gpointer) * 2);
2447 key [0] = GINT_TO_POINTER (1);
2448 key [1] = extra_class;
2451 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2452 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2453 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2454 key [1] = remote_class->proxy_class;
2456 // Keep the list of interfaces sorted
2457 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2458 if (extra_class && remote_class->interfaces [i] > extra_class) {
2459 key [j++] = extra_class;
2462 key [j] = remote_class->interfaces [i];
2465 key [j] = extra_class;
2467 // Replace the old class. The interface list is the same
2468 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2469 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2470 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2471 for (i = 0; i < remote_class->interface_count; i++)
2472 key [2 + i] = remote_class->interfaces [i];
2480 * copy_remote_class_key:
2482 * Make a copy of KEY in the domain and return the copy.
2485 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2487 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2488 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2490 memcpy (mp_key, key, key_size);
2496 * mono_remote_class:
2497 * @domain: the application domain
2498 * @class_name: name of the remote class
2500 * Creates and initializes a MonoRemoteClass object for a remote type.
2502 * Can raise an exception on failure.
2505 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2508 MonoRemoteClass *rc;
2509 gpointer* key, *mp_key;
2512 key = create_remote_class_key (NULL, proxy_class);
2514 mono_domain_lock (domain);
2515 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2519 mono_domain_unlock (domain);
2523 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2524 if (!mono_error_ok (&error)) {
2526 mono_domain_unlock (domain);
2527 mono_error_raise_exception (&error);
2530 mp_key = copy_remote_class_key (domain, key);
2534 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2535 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2536 rc->interface_count = 1;
2537 rc->interfaces [0] = proxy_class;
2538 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2540 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2541 rc->interface_count = 0;
2542 rc->proxy_class = proxy_class;
2545 rc->default_vtable = NULL;
2546 rc->xdomain_vtable = NULL;
2547 rc->proxy_class_name = name;
2548 #ifndef DISABLE_PERFCOUNTERS
2549 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2552 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2554 mono_domain_unlock (domain);
2559 * clone_remote_class:
2560 * Creates a copy of the remote_class, adding the provided class or interface
2562 static MonoRemoteClass*
2563 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2565 MonoRemoteClass *rc;
2566 gpointer* key, *mp_key;
2568 key = create_remote_class_key (remote_class, extra_class);
2569 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2575 mp_key = copy_remote_class_key (domain, key);
2579 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2581 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2582 rc->proxy_class = remote_class->proxy_class;
2583 rc->interface_count = remote_class->interface_count + 1;
2585 // Keep the list of interfaces sorted, since the hash key of
2586 // the remote class depends on this
2587 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2588 if (remote_class->interfaces [i] > extra_class && i == j)
2589 rc->interfaces [j++] = extra_class;
2590 rc->interfaces [j] = remote_class->interfaces [i];
2593 rc->interfaces [j] = extra_class;
2595 // Replace the old class. The interface array is the same
2596 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2597 rc->proxy_class = extra_class;
2598 rc->interface_count = remote_class->interface_count;
2599 if (rc->interface_count > 0)
2600 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2603 rc->default_vtable = NULL;
2604 rc->xdomain_vtable = NULL;
2605 rc->proxy_class_name = remote_class->proxy_class_name;
2607 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2613 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2615 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2616 mono_domain_lock (domain);
2617 if (rp->target_domain_id != -1) {
2618 if (remote_class->xdomain_vtable == NULL)
2619 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2620 mono_domain_unlock (domain);
2621 mono_loader_unlock ();
2622 return remote_class->xdomain_vtable;
2624 if (remote_class->default_vtable == NULL) {
2627 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2628 klass = mono_class_from_mono_type (type);
2630 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2631 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2634 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2637 mono_domain_unlock (domain);
2638 mono_loader_unlock ();
2639 return remote_class->default_vtable;
2643 * mono_upgrade_remote_class:
2644 * @domain: the application domain
2645 * @tproxy: the proxy whose remote class has to be upgraded.
2646 * @klass: class to which the remote class can be casted.
2648 * Updates the vtable of the remote class by adding the necessary method slots
2649 * and interface offsets so it can be safely casted to klass. klass can be a
2650 * class or an interface.
2653 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2655 MonoTransparentProxy *tproxy;
2656 MonoRemoteClass *remote_class;
2657 gboolean redo_vtable;
2659 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2660 mono_domain_lock (domain);
2662 tproxy = (MonoTransparentProxy*) proxy_object;
2663 remote_class = tproxy->remote_class;
2665 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2668 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2669 if (remote_class->interfaces [i] == klass)
2670 redo_vtable = FALSE;
2673 redo_vtable = (remote_class->proxy_class != klass);
2677 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2678 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2681 mono_domain_unlock (domain);
2682 mono_loader_unlock ();
2684 #endif /* DISABLE_REMOTING */
2688 * mono_object_get_virtual_method:
2689 * @obj: object to operate on.
2692 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2693 * the instance of a callvirt of method.
2696 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2699 MonoMethod **vtable;
2700 gboolean is_proxy = FALSE;
2701 MonoMethod *res = NULL;
2703 klass = mono_object_class (obj);
2704 #ifndef DISABLE_REMOTING
2705 if (klass == mono_defaults.transparent_proxy_class) {
2706 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2711 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2714 mono_class_setup_vtable (klass);
2715 vtable = klass->vtable;
2717 if (method->slot == -1) {
2718 /* method->slot might not be set for instances of generic methods */
2719 if (method->is_inflated) {
2720 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2721 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2724 g_assert_not_reached ();
2728 /* check method->slot is a valid index: perform isinstance? */
2729 if (method->slot != -1) {
2730 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2732 gboolean variance_used = FALSE;
2733 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2734 g_assert (iface_offset > 0);
2735 res = vtable [iface_offset + method->slot];
2738 res = vtable [method->slot];
2742 #ifndef DISABLE_REMOTING
2744 /* It may be an interface, abstract class method or generic method */
2745 if (!res || mono_method_signature (res)->generic_param_count)
2748 /* generic methods demand invoke_with_check */
2749 if (mono_method_signature (res)->generic_param_count)
2750 res = mono_marshal_get_remoting_invoke_with_check (res);
2753 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2754 res = mono_cominterop_get_invoke (res);
2757 res = mono_marshal_get_remoting_invoke (res);
2762 if (method->is_inflated) {
2763 /* Have to inflate the result */
2764 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2774 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2776 g_error ("runtime invoke called on uninitialized runtime");
2780 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2783 * mono_runtime_invoke:
2784 * @method: method to invoke
2785 * @obJ: object instance
2786 * @params: arguments to the method
2787 * @exc: exception information.
2789 * Invokes the method represented by @method on the object @obj.
2791 * obj is the 'this' pointer, it should be NULL for static
2792 * methods, a MonoObject* for object instances and a pointer to
2793 * the value type for value types.
2795 * The params array contains the arguments to the method with the
2796 * same convention: MonoObject* pointers for object instances and
2797 * pointers to the value type otherwise.
2799 * From unmanaged code you'll usually use the
2800 * mono_runtime_invoke() variant.
2802 * Note that this function doesn't handle virtual methods for
2803 * you, it will exec the exact method you pass: we still need to
2804 * expose a function to lookup the derived class implementation
2805 * of a virtual method (there are examples of this in the code,
2808 * You can pass NULL as the exc argument if you don't want to
2809 * catch exceptions, otherwise, *exc will be set to the exception
2810 * thrown, if any. if an exception is thrown, you can't use the
2811 * MonoObject* result from the function.
2813 * If the method returns a value type, it is boxed in an object
2817 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2821 if (mono_runtime_get_no_exec ())
2822 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2824 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2825 mono_profiler_method_start_invoke (method);
2827 result = default_mono_runtime_invoke (method, obj, params, exc);
2829 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2830 mono_profiler_method_end_invoke (method);
2836 * mono_method_get_unmanaged_thunk:
2837 * @method: method to generate a thunk for.
2839 * Returns an unmanaged->managed thunk that can be used to call
2840 * a managed method directly from C.
2842 * The thunk's C signature closely matches the managed signature:
2844 * C#: public bool Equals (object obj);
2845 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2846 * MonoObject*, MonoException**);
2848 * The 1st ("this") parameter must not be used with static methods:
2850 * C#: public static bool ReferenceEquals (object a, object b);
2851 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2854 * The last argument must be a non-null pointer of a MonoException* pointer.
2855 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2856 * exception has been thrown in managed code. Otherwise it will point
2857 * to the MonoException* caught by the thunk. In this case, the result of
2858 * the thunk is undefined:
2860 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2861 * MonoException *ex = NULL;
2862 * Equals func = mono_method_get_unmanaged_thunk (method);
2863 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2865 * // handle exception
2868 * The calling convention of the thunk matches the platform's default
2869 * convention. This means that under Windows, C declarations must
2870 * contain the __stdcall attribute:
2872 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2873 * MonoObject*, MonoException**);
2877 * Value type arguments and return values are treated as they were objects:
2879 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2880 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2882 * Arguments must be properly boxed upon trunk's invocation, while return
2883 * values must be unboxed.
2886 mono_method_get_unmanaged_thunk (MonoMethod *method)
2888 method = mono_marshal_get_thunk_invoke_wrapper (method);
2889 return mono_compile_method (method);
2893 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2897 /* object fields cannot be byref, so we don't need a
2899 gpointer *p = (gpointer*)dest;
2906 case MONO_TYPE_BOOLEAN:
2908 case MONO_TYPE_U1: {
2909 guint8 *p = (guint8*)dest;
2910 *p = value ? *(guint8*)value : 0;
2915 case MONO_TYPE_CHAR: {
2916 guint16 *p = (guint16*)dest;
2917 *p = value ? *(guint16*)value : 0;
2920 #if SIZEOF_VOID_P == 4
2925 case MONO_TYPE_U4: {
2926 gint32 *p = (gint32*)dest;
2927 *p = value ? *(gint32*)value : 0;
2930 #if SIZEOF_VOID_P == 8
2935 case MONO_TYPE_U8: {
2936 gint64 *p = (gint64*)dest;
2937 *p = value ? *(gint64*)value : 0;
2940 case MONO_TYPE_R4: {
2941 float *p = (float*)dest;
2942 *p = value ? *(float*)value : 0;
2945 case MONO_TYPE_R8: {
2946 double *p = (double*)dest;
2947 *p = value ? *(double*)value : 0;
2950 case MONO_TYPE_STRING:
2951 case MONO_TYPE_SZARRAY:
2952 case MONO_TYPE_CLASS:
2953 case MONO_TYPE_OBJECT:
2954 case MONO_TYPE_ARRAY:
2955 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2957 case MONO_TYPE_FNPTR:
2958 case MONO_TYPE_PTR: {
2959 gpointer *p = (gpointer*)dest;
2960 *p = deref_pointer? *(gpointer*)value: value;
2963 case MONO_TYPE_VALUETYPE:
2964 /* note that 't' and 'type->type' can be different */
2965 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2966 t = mono_class_enum_basetype (type->data.klass)->type;
2969 MonoClass *class = mono_class_from_mono_type (type);
2970 int size = mono_class_value_size (class, NULL);
2972 mono_gc_bzero (dest, size);
2974 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2977 case MONO_TYPE_GENERICINST:
2978 t = type->data.generic_class->container_class->byval_arg.type;
2981 g_error ("got type %x", type->type);
2986 * mono_field_set_value:
2987 * @obj: Instance object
2988 * @field: MonoClassField describing the field to set
2989 * @value: The value to be set
2991 * Sets the value of the field described by @field in the object instance @obj
2992 * to the value passed in @value. This method should only be used for instance
2993 * fields. For static fields, use mono_field_static_set_value.
2995 * The value must be on the native format of the field type.
2998 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3002 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3004 dest = (char*)obj + field->offset;
3005 set_value (field->type, dest, value, FALSE);
3009 * mono_field_static_set_value:
3010 * @field: MonoClassField describing the field to set
3011 * @value: The value to be set
3013 * Sets the value of the static field described by @field
3014 * to the value passed in @value.
3016 * The value must be on the native format of the field type.
3019 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3023 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3024 /* you cant set a constant! */
3025 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3027 if (field->offset == -1) {
3028 /* Special static */
3031 mono_domain_lock (vt->domain);
3032 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3033 mono_domain_unlock (vt->domain);
3034 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3036 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3038 set_value (field->type, dest, value, FALSE);
3042 * mono_vtable_get_static_field_data:
3044 * Internal use function: return a pointer to the memory holding the static fields
3045 * for a class or NULL if there are no static fields.
3046 * This is exported only for use by the debugger.
3049 mono_vtable_get_static_field_data (MonoVTable *vt)
3051 if (!vt->has_static_fields)
3053 return vt->vtable [vt->klass->vtable_size];
3057 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3061 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3062 if (field->offset == -1) {
3063 /* Special static */
3066 mono_domain_lock (vt->domain);
3067 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3068 mono_domain_unlock (vt->domain);
3069 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3071 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3074 src = (guint8*)obj + field->offset;
3081 * mono_field_get_value:
3082 * @obj: Object instance
3083 * @field: MonoClassField describing the field to fetch information from
3084 * @value: pointer to the location where the value will be stored
3086 * Use this routine to get the value of the field @field in the object
3089 * The pointer provided by value must be of the field type, for reference
3090 * types this is a MonoObject*, for value types its the actual pointer to
3095 * mono_field_get_value (obj, int_field, &i);
3098 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3104 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3106 src = (char*)obj + field->offset;
3107 set_value (field->type, value, src, TRUE);
3111 * mono_field_get_value_object:
3112 * @domain: domain where the object will be created (if boxing)
3113 * @field: MonoClassField describing the field to fetch information from
3114 * @obj: The object instance for the field.
3116 * Returns: a new MonoObject with the value from the given field. If the
3117 * field represents a value type, the value is boxed.
3121 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3125 MonoVTable *vtable = NULL;
3127 gboolean is_static = FALSE;
3128 gboolean is_ref = FALSE;
3129 gboolean is_literal = FALSE;
3130 gboolean is_ptr = FALSE;
3132 MonoType *type = mono_field_get_type_checked (field, &error);
3134 if (!mono_error_ok (&error))
3135 mono_error_raise_exception (&error);
3137 switch (type->type) {
3138 case MONO_TYPE_STRING:
3139 case MONO_TYPE_OBJECT:
3140 case MONO_TYPE_CLASS:
3141 case MONO_TYPE_ARRAY:
3142 case MONO_TYPE_SZARRAY:
3147 case MONO_TYPE_BOOLEAN:
3150 case MONO_TYPE_CHAR:
3159 case MONO_TYPE_VALUETYPE:
3160 is_ref = type->byref;
3162 case MONO_TYPE_GENERICINST:
3163 is_ref = !mono_type_generic_inst_is_valuetype (type);
3169 g_error ("type 0x%x not handled in "
3170 "mono_field_get_value_object", type->type);
3174 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3177 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3181 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3182 if (!vtable->initialized)
3183 mono_runtime_class_init (vtable);
3191 get_default_field_value (domain, field, &o);
3192 } else if (is_static) {
3193 mono_field_static_get_value (vtable, field, &o);
3195 mono_field_get_value (obj, field, &o);
3201 static MonoMethod *m;
3207 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3208 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3214 get_default_field_value (domain, field, v);
3215 } else if (is_static) {
3216 mono_field_static_get_value (vtable, field, v);
3218 mono_field_get_value (obj, field, v);
3221 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3223 args [1] = mono_type_get_object (mono_domain_get (), type);
3225 return mono_runtime_invoke (m, NULL, args, NULL);
3228 /* boxed value type */
3229 klass = mono_class_from_mono_type (type);
3231 if (mono_class_is_nullable (klass))
3232 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3234 o = mono_object_new (domain, klass);
3235 v = ((gchar *) o) + sizeof (MonoObject);
3238 get_default_field_value (domain, field, v);
3239 } else if (is_static) {
3240 mono_field_static_get_value (vtable, field, v);
3242 mono_field_get_value (obj, field, v);
3249 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3252 const char *p = blob;
3253 mono_metadata_decode_blob_size (p, &p);
3256 case MONO_TYPE_BOOLEAN:
3259 *(guint8 *) value = *p;
3261 case MONO_TYPE_CHAR:
3264 *(guint16*) value = read16 (p);
3268 *(guint32*) value = read32 (p);
3272 *(guint64*) value = read64 (p);
3275 readr4 (p, (float*) value);
3278 readr8 (p, (double*) value);
3280 case MONO_TYPE_STRING:
3281 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3283 case MONO_TYPE_CLASS:
3284 *(gpointer*) value = NULL;
3288 g_warning ("type 0x%02x should not be in constant table", type);
3294 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3296 MonoTypeEnum def_type;
3299 data = mono_class_get_field_default_value (field, &def_type);
3300 mono_get_constant_value_from_blob (domain, def_type, data, value);
3304 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3308 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3310 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3311 get_default_field_value (vt->domain, field, value);
3315 if (field->offset == -1) {
3316 /* Special static */
3317 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3318 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3320 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3322 set_value (field->type, value, src, TRUE);
3326 * mono_field_static_get_value:
3327 * @vt: vtable to the object
3328 * @field: MonoClassField describing the field to fetch information from
3329 * @value: where the value is returned
3331 * Use this routine to get the value of the static field @field value.
3333 * The pointer provided by value must be of the field type, for reference
3334 * types this is a MonoObject*, for value types its the actual pointer to
3339 * mono_field_static_get_value (vt, int_field, &i);
3342 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3344 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3348 * mono_property_set_value:
3349 * @prop: MonoProperty to set
3350 * @obj: instance object on which to act
3351 * @params: parameters to pass to the propery
3352 * @exc: optional exception
3354 * Invokes the property's set method with the given arguments on the
3355 * object instance obj (or NULL for static properties).
3357 * You can pass NULL as the exc argument if you don't want to
3358 * catch exceptions, otherwise, *exc will be set to the exception
3359 * thrown, if any. if an exception is thrown, you can't use the
3360 * MonoObject* result from the function.
3363 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3365 default_mono_runtime_invoke (prop->set, obj, params, exc);
3369 * mono_property_get_value:
3370 * @prop: MonoProperty to fetch
3371 * @obj: instance object on which to act
3372 * @params: parameters to pass to the propery
3373 * @exc: optional exception
3375 * Invokes the property's get method with the given arguments on the
3376 * object instance obj (or NULL for static properties).
3378 * You can pass NULL as the exc argument if you don't want to
3379 * catch exceptions, otherwise, *exc will be set to the exception
3380 * thrown, if any. if an exception is thrown, you can't use the
3381 * MonoObject* result from the function.
3383 * Returns: the value from invoking the get method on the property.
3386 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3388 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3392 * mono_nullable_init:
3393 * @buf: The nullable structure to initialize.
3394 * @value: the value to initialize from
3395 * @klass: the type for the object
3397 * Initialize the nullable structure pointed to by @buf from @value which
3398 * should be a boxed value type. The size of @buf should be able to hold
3399 * as much data as the @klass->instance_size (which is the number of bytes
3400 * that will be copies).
3402 * Since Nullables have variable structure, we can not define a C
3403 * structure for them.
3406 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3408 MonoClass *param_class = klass->cast_class;
3410 mono_class_setup_fields_locking (klass);
3411 g_assert (klass->fields_inited);
3413 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3414 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3416 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3418 if (param_class->has_references)
3419 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3421 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3423 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3428 * mono_nullable_box:
3429 * @buf: The buffer representing the data to be boxed
3430 * @klass: the type to box it as.
3432 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3436 mono_nullable_box (guint8 *buf, MonoClass *klass)
3438 MonoClass *param_class = klass->cast_class;
3440 mono_class_setup_fields_locking (klass);
3441 g_assert (klass->fields_inited);
3443 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3444 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3446 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3447 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3448 if (param_class->has_references)
3449 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3451 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3459 * mono_get_delegate_invoke:
3460 * @klass: The delegate class
3462 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3465 mono_get_delegate_invoke (MonoClass *klass)
3469 /* This is called at runtime, so avoid the slower search in metadata */
3470 mono_class_setup_methods (klass);
3471 if (klass->exception_type)
3473 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3478 * mono_get_delegate_begin_invoke:
3479 * @klass: The delegate class
3481 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3484 mono_get_delegate_begin_invoke (MonoClass *klass)
3488 /* This is called at runtime, so avoid the slower search in metadata */
3489 mono_class_setup_methods (klass);
3490 if (klass->exception_type)
3492 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3497 * mono_get_delegate_end_invoke:
3498 * @klass: The delegate class
3500 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3503 mono_get_delegate_end_invoke (MonoClass *klass)
3507 /* This is called at runtime, so avoid the slower search in metadata */
3508 mono_class_setup_methods (klass);
3509 if (klass->exception_type)
3511 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3516 * mono_runtime_delegate_invoke:
3517 * @delegate: pointer to a delegate object.
3518 * @params: parameters for the delegate.
3519 * @exc: Pointer to the exception result.
3521 * Invokes the delegate method @delegate with the parameters provided.
3523 * You can pass NULL as the exc argument if you don't want to
3524 * catch exceptions, otherwise, *exc will be set to the exception
3525 * thrown, if any. if an exception is thrown, you can't use the
3526 * MonoObject* result from the function.
3529 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3532 MonoClass *klass = delegate->vtable->klass;
3534 im = mono_get_delegate_invoke (klass);
3536 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3538 return mono_runtime_invoke (im, delegate, params, exc);
3541 static char **main_args = NULL;
3542 static int num_main_args;
3545 * mono_runtime_get_main_args:
3547 * Returns: a MonoArray with the arguments passed to the main program
3550 mono_runtime_get_main_args (void)
3554 MonoDomain *domain = mono_domain_get ();
3559 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3561 for (i = 0; i < num_main_args; ++i)
3562 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3568 free_main_args (void)
3572 for (i = 0; i < num_main_args; ++i)
3573 g_free (main_args [i]);
3578 * mono_runtime_run_main:
3579 * @method: the method to start the application with (usually Main)
3580 * @argc: number of arguments from the command line
3581 * @argv: array of strings from the command line
3582 * @exc: excetption results
3584 * Execute a standard Main() method (argc/argv contains the
3585 * executable name). This method also sets the command line argument value
3586 * needed by System.Environment.
3591 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3595 MonoArray *args = NULL;
3596 MonoDomain *domain = mono_domain_get ();
3597 gchar *utf8_fullpath;
3598 MonoMethodSignature *sig;
3600 g_assert (method != NULL);
3602 mono_thread_set_main (mono_thread_current ());
3604 main_args = g_new0 (char*, argc);
3605 num_main_args = argc;
3607 if (!g_path_is_absolute (argv [0])) {
3608 gchar *basename = g_path_get_basename (argv [0]);
3609 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3613 utf8_fullpath = mono_utf8_from_external (fullpath);
3614 if(utf8_fullpath == NULL) {
3615 /* Printing the arg text will cause glib to
3616 * whinge about "Invalid UTF-8", but at least
3617 * its relevant, and shows the problem text
3620 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3621 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3628 utf8_fullpath = mono_utf8_from_external (argv[0]);
3629 if(utf8_fullpath == NULL) {
3630 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3631 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3636 main_args [0] = utf8_fullpath;
3638 for (i = 1; i < argc; ++i) {
3641 utf8_arg=mono_utf8_from_external (argv[i]);
3642 if(utf8_arg==NULL) {
3643 /* Ditto the comment about Invalid UTF-8 here */
3644 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3645 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3649 main_args [i] = utf8_arg;
3654 sig = mono_method_signature (method);
3656 g_print ("Unable to load Main method.\n");
3660 if (sig->param_count) {
3661 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3662 for (i = 0; i < argc; ++i) {
3663 /* The encodings should all work, given that
3664 * we've checked all these args for the
3667 gchar *str = mono_utf8_from_external (argv [i]);
3668 MonoString *arg = mono_string_new (domain, str);
3669 mono_array_setref (args, i, arg);
3673 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3676 mono_assembly_set_main (method->klass->image->assembly);
3678 return mono_runtime_exec_main (method, args, exc);
3682 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3684 static MonoMethod *serialize_method;
3689 if (!serialize_method) {
3690 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3691 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3694 if (!serialize_method) {
3699 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3703 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3711 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3713 static MonoMethod *deserialize_method;
3718 if (!deserialize_method) {
3719 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3720 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3722 if (!deserialize_method) {
3729 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3736 #ifndef DISABLE_REMOTING
3738 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3740 static MonoMethod *get_proxy_method;
3742 MonoDomain *domain = mono_domain_get ();
3743 MonoRealProxy *real_proxy;
3744 MonoReflectionType *reflection_type;
3745 MonoTransparentProxy *transparent_proxy;
3747 if (!get_proxy_method)
3748 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3750 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3752 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3753 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3755 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3756 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3759 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3763 return (MonoObject*) transparent_proxy;
3765 #endif /* DISABLE_REMOTING */
3768 * mono_object_xdomain_representation
3770 * @target_domain: a domain
3771 * @exc: pointer to a MonoObject*
3773 * Creates a representation of obj in the domain target_domain. This
3774 * is either a copy of obj arrived through via serialization and
3775 * deserialization or a proxy, depending on whether the object is
3776 * serializable or marshal by ref. obj must not be in target_domain.
3778 * If the object cannot be represented in target_domain, NULL is
3779 * returned and *exc is set to an appropriate exception.
3782 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3784 MonoObject *deserialized = NULL;
3785 gboolean failure = FALSE;
3789 #ifndef DISABLE_REMOTING
3790 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3791 deserialized = make_transparent_proxy (obj, &failure, exc);
3796 MonoDomain *domain = mono_domain_get ();
3797 MonoObject *serialized;
3799 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3800 serialized = serialize_object (obj, &failure, exc);
3801 mono_domain_set_internal_with_options (target_domain, FALSE);
3803 deserialized = deserialize_object (serialized, &failure, exc);
3804 if (domain != target_domain)
3805 mono_domain_set_internal_with_options (domain, FALSE);
3808 return deserialized;
3811 /* Used in call_unhandled_exception_delegate */
3813 create_unhandled_exception_eventargs (MonoObject *exc)
3817 MonoMethod *method = NULL;
3818 MonoBoolean is_terminating = TRUE;
3821 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3824 mono_class_init (klass);
3826 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3827 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3831 args [1] = &is_terminating;
3833 obj = mono_object_new (mono_domain_get (), klass);
3834 mono_runtime_invoke (method, obj, args, NULL);
3839 /* Used in mono_unhandled_exception */
3841 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3842 MonoObject *e = NULL;
3844 MonoDomain *current_domain = mono_domain_get ();
3846 if (domain != current_domain)
3847 mono_domain_set_internal_with_options (domain, FALSE);
3849 g_assert (domain == mono_object_domain (domain->domain));
3851 if (mono_object_domain (exc) != domain) {
3852 MonoObject *serialization_exc;
3854 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3856 if (serialization_exc) {
3858 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3861 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3862 "System.Runtime.Serialization", "SerializationException",
3863 "Could not serialize unhandled exception.");
3867 g_assert (mono_object_domain (exc) == domain);
3869 pa [0] = domain->domain;
3870 pa [1] = create_unhandled_exception_eventargs (exc);
3871 mono_runtime_delegate_invoke (delegate, pa, &e);
3873 if (domain != current_domain)
3874 mono_domain_set_internal_with_options (current_domain, FALSE);
3878 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3879 if (!mono_error_ok (&error)) {
3880 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3881 mono_error_cleanup (&error);
3883 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3889 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3892 * mono_runtime_unhandled_exception_policy_set:
3893 * @policy: the new policy
3895 * This is a VM internal routine.
3897 * Sets the runtime policy for handling unhandled exceptions.
3900 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3901 runtime_unhandled_exception_policy = policy;
3905 * mono_runtime_unhandled_exception_policy_get:
3907 * This is a VM internal routine.
3909 * Gets the runtime policy for handling unhandled exceptions.
3911 MonoRuntimeUnhandledExceptionPolicy
3912 mono_runtime_unhandled_exception_policy_get (void) {
3913 return runtime_unhandled_exception_policy;
3917 * mono_unhandled_exception:
3918 * @exc: exception thrown
3920 * This is a VM internal routine.
3922 * We call this function when we detect an unhandled exception
3923 * in the default domain.
3925 * It invokes the * UnhandledException event in AppDomain or prints
3926 * a warning to the console
3929 mono_unhandled_exception (MonoObject *exc)
3931 MonoDomain *current_domain = mono_domain_get ();
3932 MonoDomain *root_domain = mono_get_root_domain ();
3933 MonoClassField *field;
3934 MonoObject *current_appdomain_delegate;
3935 MonoObject *root_appdomain_delegate;
3937 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3938 "UnhandledException");
3941 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3942 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3943 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3944 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3945 if (current_domain != root_domain) {
3946 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3948 current_appdomain_delegate = NULL;
3951 /* set exitcode only if we will abort the process */
3952 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3954 mono_environment_exitcode_set (1);
3955 mono_print_unhandled_exception (exc);
3957 if (root_appdomain_delegate) {
3958 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3960 if (current_appdomain_delegate) {
3961 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3968 * mono_runtime_exec_managed_code:
3969 * @domain: Application domain
3970 * @main_func: function to invoke from the execution thread
3971 * @main_args: parameter to the main_func
3973 * Launch a new thread to execute a function
3975 * main_func is called back from the thread with main_args as the
3976 * parameter. The callback function is expected to start Main()
3977 * eventually. This function then waits for all managed threads to
3979 * It is not necesseray anymore to execute managed code in a subthread,
3980 * so this function should not be used anymore by default: just
3981 * execute the code and then call mono_thread_manage ().
3984 mono_runtime_exec_managed_code (MonoDomain *domain,
3985 MonoMainThreadFunc main_func,
3988 mono_thread_create (domain, main_func, main_args);
3990 mono_thread_manage ();
3994 * Execute a standard Main() method (args doesn't contain the
3998 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4003 MonoCustomAttrInfo* cinfo;
4004 gboolean has_stathread_attribute;
4005 MonoInternalThread* thread = mono_thread_internal_current ();
4011 domain = mono_object_domain (args);
4012 if (!domain->entry_assembly) {
4014 MonoAssembly *assembly;
4016 assembly = method->klass->image->assembly;
4017 domain->entry_assembly = assembly;
4018 /* Domains created from another domain already have application_base and configuration_file set */
4019 if (domain->setup->application_base == NULL) {
4020 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4023 if (domain->setup->configuration_file == NULL) {
4024 str = g_strconcat (assembly->image->name, ".config", NULL);
4025 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4027 mono_set_private_bin_path_from_config (domain);
4031 cinfo = mono_custom_attrs_from_method (method);
4033 static MonoClass *stathread_attribute = NULL;
4034 if (!stathread_attribute)
4035 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4036 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4038 mono_custom_attrs_free (cinfo);
4040 has_stathread_attribute = FALSE;
4042 if (has_stathread_attribute) {
4043 thread->apartment_state = ThreadApartmentState_STA;
4045 thread->apartment_state = ThreadApartmentState_MTA;
4047 mono_thread_init_apartment_state ();
4049 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
4051 /* FIXME: check signature of method */
4052 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4054 res = mono_runtime_invoke (method, NULL, pa, exc);
4056 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4060 mono_environment_exitcode_set (rval);
4062 mono_runtime_invoke (method, NULL, pa, exc);
4066 /* If the return type of Main is void, only
4067 * set the exitcode if an exception was thrown
4068 * (we don't want to blow away an
4069 * explicitly-set exit code)
4072 mono_environment_exitcode_set (rval);
4076 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4082 * mono_install_runtime_invoke:
4083 * @func: Function to install
4085 * This is a VM internal routine
4088 mono_install_runtime_invoke (MonoInvokeFunc func)
4090 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4095 * mono_runtime_invoke_array:
4096 * @method: method to invoke
4097 * @obJ: object instance
4098 * @params: arguments to the method
4099 * @exc: exception information.
4101 * Invokes the method represented by @method on the object @obj.
4103 * obj is the 'this' pointer, it should be NULL for static
4104 * methods, a MonoObject* for object instances and a pointer to
4105 * the value type for value types.
4107 * The params array contains the arguments to the method with the
4108 * same convention: MonoObject* pointers for object instances and
4109 * pointers to the value type otherwise. The _invoke_array
4110 * variant takes a C# object[] as the params argument (MonoArray
4111 * *params): in this case the value types are boxed inside the
4112 * respective reference representation.
4114 * From unmanaged code you'll usually use the
4115 * mono_runtime_invoke() variant.
4117 * Note that this function doesn't handle virtual methods for
4118 * you, it will exec the exact method you pass: we still need to
4119 * expose a function to lookup the derived class implementation
4120 * of a virtual method (there are examples of this in the code,
4123 * You can pass NULL as the exc argument if you don't want to
4124 * catch exceptions, otherwise, *exc will be set to the exception
4125 * thrown, if any. if an exception is thrown, you can't use the
4126 * MonoObject* result from the function.
4128 * If the method returns a value type, it is boxed in an object
4132 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4135 MonoMethodSignature *sig = mono_method_signature (method);
4136 gpointer *pa = NULL;
4139 gboolean has_byref_nullables = FALSE;
4141 if (NULL != params) {
4142 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4143 for (i = 0; i < mono_array_length (params); i++) {
4144 MonoType *t = sig->params [i];
4150 case MONO_TYPE_BOOLEAN:
4153 case MONO_TYPE_CHAR:
4162 case MONO_TYPE_VALUETYPE:
4163 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4164 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4165 pa [i] = mono_array_get (params, MonoObject*, i);
4167 has_byref_nullables = TRUE;
4169 /* MS seems to create the objects if a null is passed in */
4170 if (!mono_array_get (params, MonoObject*, i))
4171 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4175 * We can't pass the unboxed vtype byref to the callee, since
4176 * that would mean the callee would be able to modify boxed
4177 * primitive types. So we (and MS) make a copy of the boxed
4178 * object, pass that to the callee, and replace the original
4179 * boxed object in the arg array with the copy.
4181 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4182 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4183 mono_array_setref (params, i, copy);
4186 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4189 case MONO_TYPE_STRING:
4190 case MONO_TYPE_OBJECT:
4191 case MONO_TYPE_CLASS:
4192 case MONO_TYPE_ARRAY:
4193 case MONO_TYPE_SZARRAY:
4195 pa [i] = mono_array_addr (params, MonoObject*, i);
4196 // FIXME: I need to check this code path
4198 pa [i] = mono_array_get (params, MonoObject*, i);
4200 case MONO_TYPE_GENERICINST:
4202 t = &t->data.generic_class->container_class->this_arg;
4204 t = &t->data.generic_class->container_class->byval_arg;
4206 case MONO_TYPE_PTR: {
4209 /* The argument should be an IntPtr */
4210 arg = mono_array_get (params, MonoObject*, i);
4214 g_assert (arg->vtable->klass == mono_defaults.int_class);
4215 pa [i] = ((MonoIntPtr*)arg)->m_value;
4220 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4225 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4228 if (mono_class_is_nullable (method->klass)) {
4229 /* Need to create a boxed vtype instead */
4235 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4239 obj = mono_object_new (mono_domain_get (), method->klass);
4240 g_assert (obj); /*maybe we should raise a TLE instead?*/
4241 #ifndef DISABLE_REMOTING
4242 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4243 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4246 if (method->klass->valuetype)
4247 o = mono_object_unbox (obj);
4250 } else if (method->klass->valuetype) {
4251 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4254 mono_runtime_invoke (method, o, pa, exc);
4257 if (mono_class_is_nullable (method->klass)) {
4258 MonoObject *nullable;
4260 /* Convert the unboxed vtype into a Nullable structure */
4261 nullable = mono_object_new (mono_domain_get (), method->klass);
4263 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4264 obj = mono_object_unbox (nullable);
4267 /* obj must be already unboxed if needed */
4268 res = mono_runtime_invoke (method, obj, pa, exc);
4270 if (sig->ret->type == MONO_TYPE_PTR) {
4271 MonoClass *pointer_class;
4272 static MonoMethod *box_method;
4274 MonoObject *box_exc;
4277 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4278 * convert it to a Pointer object.
4280 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4282 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4284 g_assert (res->vtable->klass == mono_defaults.int_class);
4285 box_args [0] = ((MonoIntPtr*)res)->m_value;
4286 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4287 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4288 g_assert (!box_exc);
4291 if (has_byref_nullables) {
4293 * The runtime invoke wrapper already converted byref nullables back,
4294 * and stored them in pa, we just need to copy them back to the
4297 for (i = 0; i < mono_array_length (params); i++) {
4298 MonoType *t = sig->params [i];
4300 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4301 mono_array_setref (params, i, pa [i]);
4310 arith_overflow (void)
4312 mono_raise_exception (mono_get_exception_overflow ());
4316 * mono_object_allocate:
4317 * @size: number of bytes to allocate
4319 * This is a very simplistic routine until we have our GC-aware
4322 * Returns: an allocated object of size @size, or NULL on failure.
4324 static inline void *
4325 mono_object_allocate (size_t size, MonoVTable *vtable)
4328 mono_stats.new_object_count++;
4329 ALLOC_OBJECT (o, vtable, size);
4335 * mono_object_allocate_ptrfree:
4336 * @size: number of bytes to allocate
4338 * Note that the memory allocated is not zeroed.
4339 * Returns: an allocated object of size @size, or NULL on failure.
4341 static inline void *
4342 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4345 mono_stats.new_object_count++;
4346 ALLOC_PTRFREE (o, vtable, size);
4350 static inline void *
4351 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4354 ALLOC_TYPED (o, size, vtable);
4355 mono_stats.new_object_count++;
4362 * @klass: the class of the object that we want to create
4364 * Returns: a newly created object whose definition is
4365 * looked up using @klass. This will not invoke any constructors,
4366 * so the consumer of this routine has to invoke any constructors on
4367 * its own to initialize the object.
4369 * It returns NULL on failure.
4372 mono_object_new (MonoDomain *domain, MonoClass *klass)
4376 MONO_ARCH_SAVE_REGS;
4377 vtable = mono_class_vtable (domain, klass);
4380 return mono_object_new_specific (vtable);
4384 * mono_object_new_pinned:
4386 * Same as mono_object_new, but the returned object will be pinned.
4387 * For SGEN, these objects will only be freed at appdomain unload.
4390 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4394 MONO_ARCH_SAVE_REGS;
4395 vtable = mono_class_vtable (domain, klass);
4400 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4402 return mono_object_new_specific (vtable);
4407 * mono_object_new_specific:
4408 * @vtable: the vtable of the object that we want to create
4410 * Returns: A newly created object with class and domain specified
4414 mono_object_new_specific (MonoVTable *vtable)
4418 MONO_ARCH_SAVE_REGS;
4420 /* check for is_com_object for COM Interop */
4421 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4424 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4427 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4430 mono_class_init (klass);
4432 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4434 vtable->domain->create_proxy_for_type_method = im;
4437 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4439 o = mono_runtime_invoke (im, NULL, pa, NULL);
4440 if (o != NULL) return o;
4443 return mono_object_new_alloc_specific (vtable);
4447 mono_object_new_alloc_specific (MonoVTable *vtable)
4451 if (!vtable->klass->has_references) {
4452 o = mono_object_new_ptrfree (vtable);
4453 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4454 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4456 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4457 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4459 if (G_UNLIKELY (vtable->klass->has_finalize))
4460 mono_object_register_finalizer (o);
4462 if (G_UNLIKELY (profile_allocs))
4463 mono_profiler_allocation (o, vtable->klass);
4468 mono_object_new_fast (MonoVTable *vtable)
4471 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4476 mono_object_new_ptrfree (MonoVTable *vtable)
4479 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4480 #if NEED_TO_ZERO_PTRFREE
4481 /* an inline memset is much faster for the common vcase of small objects
4482 * note we assume the allocated size is a multiple of sizeof (void*).
4484 if (vtable->klass->instance_size < 128) {
4486 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4487 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4493 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4500 mono_object_new_ptrfree_box (MonoVTable *vtable)
4503 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4504 /* the object will be boxed right away, no need to memzero it */
4509 * mono_class_get_allocation_ftn:
4511 * @for_box: the object will be used for boxing
4512 * @pass_size_in_words:
4514 * Return the allocation function appropriate for the given class.
4518 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4520 *pass_size_in_words = FALSE;
4522 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4523 profile_allocs = FALSE;
4525 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4526 return mono_object_new_specific;
4528 if (!vtable->klass->has_references) {
4529 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4531 return mono_object_new_ptrfree_box;
4532 return mono_object_new_ptrfree;
4535 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4537 return mono_object_new_fast;
4540 * FIXME: This is actually slower than mono_object_new_fast, because
4541 * of the overhead of parameter passing.
4544 *pass_size_in_words = TRUE;
4545 #ifdef GC_REDIRECT_TO_LOCAL
4546 return GC_local_gcj_fast_malloc;
4548 return GC_gcj_fast_malloc;
4553 return mono_object_new_specific;
4557 * mono_object_new_from_token:
4558 * @image: Context where the type_token is hosted
4559 * @token: a token of the type that we want to create
4561 * Returns: A newly created object whose definition is
4562 * looked up using @token in the @image image
4565 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4569 class = mono_class_get (image, token);
4571 return mono_object_new (domain, class);
4576 * mono_object_clone:
4577 * @obj: the object to clone
4579 * Returns: A newly created object who is a shallow copy of @obj
4582 mono_object_clone (MonoObject *obj)
4585 int size = obj->vtable->klass->instance_size;
4587 if (obj->vtable->klass->rank)
4588 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4590 o = mono_object_allocate (size, obj->vtable);
4592 if (obj->vtable->klass->has_references) {
4593 mono_gc_wbarrier_object_copy (o, obj);
4595 int size = obj->vtable->klass->instance_size;
4596 /* do not copy the sync state */
4597 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4599 if (G_UNLIKELY (profile_allocs))
4600 mono_profiler_allocation (o, obj->vtable->klass);
4602 if (obj->vtable->klass->has_finalize)
4603 mono_object_register_finalizer (o);
4608 * mono_array_full_copy:
4609 * @src: source array to copy
4610 * @dest: destination array
4612 * Copies the content of one array to another with exactly the same type and size.
4615 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4618 MonoClass *klass = src->obj.vtable->klass;
4620 MONO_ARCH_SAVE_REGS;
4622 g_assert (klass == dest->obj.vtable->klass);
4624 size = mono_array_length (src);
4625 g_assert (size == mono_array_length (dest));
4626 size *= mono_array_element_size (klass);
4628 if (klass->element_class->valuetype) {
4629 if (klass->element_class->has_references)
4630 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4632 mono_gc_memmove (&dest->vector, &src->vector, size);
4634 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4637 mono_gc_memmove (&dest->vector, &src->vector, size);
4642 * mono_array_clone_in_domain:
4643 * @domain: the domain in which the array will be cloned into
4644 * @array: the array to clone
4646 * This routine returns a copy of the array that is hosted on the
4647 * specified MonoDomain.
4650 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4655 MonoClass *klass = array->obj.vtable->klass;
4657 MONO_ARCH_SAVE_REGS;
4659 if (array->bounds == NULL) {
4660 size = mono_array_length (array);
4661 o = mono_array_new_full (domain, klass, &size, NULL);
4663 size *= mono_array_element_size (klass);
4665 if (klass->element_class->valuetype) {
4666 if (klass->element_class->has_references)
4667 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4669 mono_gc_memmove (&o->vector, &array->vector, size);
4671 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4674 mono_gc_memmove (&o->vector, &array->vector, size);
4679 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4680 size = mono_array_element_size (klass);
4681 for (i = 0; i < klass->rank; ++i) {
4682 sizes [i] = array->bounds [i].length;
4683 size *= array->bounds [i].length;
4684 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4686 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4688 if (klass->element_class->valuetype) {
4689 if (klass->element_class->has_references)
4690 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4692 mono_gc_memmove (&o->vector, &array->vector, size);
4694 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4697 mono_gc_memmove (&o->vector, &array->vector, size);
4705 * @array: the array to clone
4707 * Returns: A newly created array who is a shallow copy of @array
4710 mono_array_clone (MonoArray *array)
4712 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4715 /* helper macros to check for overflow when calculating the size of arrays */
4716 #ifdef MONO_BIG_ARRAYS
4717 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4718 #define MYGUINT_MAX MYGUINT64_MAX
4719 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4720 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4721 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4722 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4723 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4725 #define MYGUINT32_MAX 4294967295U
4726 #define MYGUINT_MAX MYGUINT32_MAX
4727 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4728 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4729 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4730 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4731 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4735 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4739 byte_len = mono_array_element_size (class);
4740 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4743 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4745 byte_len += sizeof (MonoArray);
4753 * mono_array_new_full:
4754 * @domain: domain where the object is created
4755 * @array_class: array class
4756 * @lengths: lengths for each dimension in the array
4757 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4759 * This routine creates a new array objects with the given dimensions,
4760 * lower bounds and type.
4763 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4765 uintptr_t byte_len, len, bounds_size;
4768 MonoArrayBounds *bounds;
4772 if (!array_class->inited)
4773 mono_class_init (array_class);
4777 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4778 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4780 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4784 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4786 for (i = 0; i < array_class->rank; ++i) {
4787 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4789 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4790 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4795 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4796 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4800 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4801 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4802 byte_len = (byte_len + 3) & ~3;
4803 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4804 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4805 byte_len += bounds_size;
4808 * Following three lines almost taken from mono_object_new ():
4809 * they need to be kept in sync.
4811 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4812 #ifndef HAVE_SGEN_GC
4813 if (!array_class->has_references) {
4814 o = mono_object_allocate_ptrfree (byte_len, vtable);
4815 #if NEED_TO_ZERO_PTRFREE
4816 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4818 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4819 o = mono_object_allocate_spec (byte_len, vtable);
4821 o = mono_object_allocate (byte_len, vtable);
4824 array = (MonoArray*)o;
4825 array->max_length = len;
4828 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4829 array->bounds = bounds;
4833 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4835 o = mono_gc_alloc_vector (vtable, byte_len, len);
4836 array = (MonoArray*)o;
4837 mono_stats.new_object_count++;
4839 bounds = array->bounds;
4843 for (i = 0; i < array_class->rank; ++i) {
4844 bounds [i].length = lengths [i];
4846 bounds [i].lower_bound = lower_bounds [i];
4850 if (G_UNLIKELY (profile_allocs))
4851 mono_profiler_allocation (o, array_class);
4858 * @domain: domain where the object is created
4859 * @eclass: element class
4860 * @n: number of array elements
4862 * This routine creates a new szarray with @n elements of type @eclass.
4865 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4869 MONO_ARCH_SAVE_REGS;
4871 ac = mono_array_class_get (eclass, 1);
4874 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4878 * mono_array_new_specific:
4879 * @vtable: a vtable in the appropriate domain for an initialized class
4880 * @n: number of array elements
4882 * This routine is a fast alternative to mono_array_new() for code which
4883 * can be sure about the domain it operates in.
4886 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4892 MONO_ARCH_SAVE_REGS;
4894 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4899 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4900 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4903 #ifndef HAVE_SGEN_GC
4904 if (!vtable->klass->has_references) {
4905 o = mono_object_allocate_ptrfree (byte_len, vtable);
4906 #if NEED_TO_ZERO_PTRFREE
4907 ((MonoArray*)o)->bounds = NULL;
4908 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4910 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4911 o = mono_object_allocate_spec (byte_len, vtable);
4913 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4914 o = mono_object_allocate (byte_len, vtable);
4917 ao = (MonoArray *)o;
4920 o = mono_gc_alloc_vector (vtable, byte_len, n);
4922 mono_stats.new_object_count++;
4925 if (G_UNLIKELY (profile_allocs))
4926 mono_profiler_allocation (o, vtable->klass);
4932 * mono_string_new_utf16:
4933 * @text: a pointer to an utf16 string
4934 * @len: the length of the string
4936 * Returns: A newly created string object which contains @text.
4939 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4943 s = mono_string_new_size (domain, len);
4944 g_assert (s != NULL);
4946 memcpy (mono_string_chars (s), text, len * 2);
4952 * mono_string_new_size:
4953 * @text: a pointer to an utf16 string
4954 * @len: the length of the string
4956 * Returns: A newly created string object of @len
4959 mono_string_new_size (MonoDomain *domain, gint32 len)
4963 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4965 /* overflow ? can't fit it, can't allocate it! */
4967 mono_gc_out_of_memory (-1);
4969 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4972 #ifndef HAVE_SGEN_GC
4973 s = mono_object_allocate_ptrfree (size, vtable);
4977 s = mono_gc_alloc_string (vtable, size, len);
4979 #if NEED_TO_ZERO_PTRFREE
4982 if (G_UNLIKELY (profile_allocs))
4983 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4989 * mono_string_new_len:
4990 * @text: a pointer to an utf8 string
4991 * @length: number of bytes in @text to consider
4993 * Returns: A newly created string object which contains @text.
4996 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4998 GError *error = NULL;
4999 MonoString *o = NULL;
5001 glong items_written;
5003 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5006 o = mono_string_new_utf16 (domain, ut, items_written);
5008 g_error_free (error);
5017 * @text: a pointer to an utf8 string
5019 * Returns: A newly created string object which contains @text.
5022 mono_string_new (MonoDomain *domain, const char *text)
5024 GError *error = NULL;
5025 MonoString *o = NULL;
5027 glong items_written;
5032 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5035 o = mono_string_new_utf16 (domain, ut, items_written);
5037 g_error_free (error);
5040 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5045 MonoString *o = NULL;
5047 if (!g_utf8_validate (text, -1, &end))
5050 len = g_utf8_strlen (text, -1);
5051 o = mono_string_new_size (domain, len);
5052 str = mono_string_chars (o);
5054 while (text < end) {
5055 *str++ = g_utf8_get_char (text);
5056 text = g_utf8_next_char (text);
5063 * mono_string_new_wrapper:
5064 * @text: pointer to utf8 characters.
5066 * Helper function to create a string object from @text in the current domain.
5069 mono_string_new_wrapper (const char *text)
5071 MonoDomain *domain = mono_domain_get ();
5073 MONO_ARCH_SAVE_REGS;
5076 return mono_string_new (domain, text);
5083 * @class: the class of the value
5084 * @value: a pointer to the unboxed data
5086 * Returns: A newly created object which contains @value.
5089 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5095 g_assert (class->valuetype);
5096 if (mono_class_is_nullable (class))
5097 return mono_nullable_box (value, class);
5099 vtable = mono_class_vtable (domain, class);
5102 size = mono_class_instance_size (class);
5103 res = mono_object_new_alloc_specific (vtable);
5104 if (G_UNLIKELY (profile_allocs))
5105 mono_profiler_allocation (res, class);
5107 size = size - sizeof (MonoObject);
5110 g_assert (size == mono_class_value_size (class, NULL));
5111 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5113 #if NO_UNALIGNED_ACCESS
5114 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5118 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5121 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5124 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5127 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5130 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5134 if (class->has_finalize)
5135 mono_object_register_finalizer (res);
5141 * @dest: destination pointer
5142 * @src: source pointer
5143 * @klass: a valuetype class
5145 * Copy a valuetype from @src to @dest. This function must be used
5146 * when @klass contains references fields.
5149 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5151 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5155 * mono_value_copy_array:
5156 * @dest: destination array
5157 * @dest_idx: index in the @dest array
5158 * @src: source pointer
5159 * @count: number of items
5161 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5162 * This function must be used when @klass contains references fields.
5163 * Overlap is handled.
5166 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5168 int size = mono_array_element_size (dest->obj.vtable->klass);
5169 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5170 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5171 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5175 * mono_object_get_domain:
5176 * @obj: object to query
5178 * Returns: the MonoDomain where the object is hosted
5181 mono_object_get_domain (MonoObject *obj)
5183 return mono_object_domain (obj);
5187 * mono_object_get_class:
5188 * @obj: object to query
5190 * Returns: the MonOClass of the object.
5193 mono_object_get_class (MonoObject *obj)
5195 return mono_object_class (obj);
5198 * mono_object_get_size:
5199 * @o: object to query
5201 * Returns: the size, in bytes, of @o
5204 mono_object_get_size (MonoObject* o)
5206 MonoClass* klass = mono_object_class (o);
5207 if (klass == mono_defaults.string_class) {
5208 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5209 } else if (o->vtable->rank) {
5210 MonoArray *array = (MonoArray*)o;
5211 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5212 if (array->bounds) {
5215 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5219 return mono_class_instance_size (klass);
5224 * mono_object_unbox:
5225 * @obj: object to unbox
5227 * Returns: a pointer to the start of the valuetype boxed in this
5230 * This method will assert if the object passed is not a valuetype.
5233 mono_object_unbox (MonoObject *obj)
5235 /* add assert for valuetypes? */
5236 g_assert (obj->vtable->klass->valuetype);
5237 return ((char*)obj) + sizeof (MonoObject);
5241 * mono_object_isinst:
5243 * @klass: a pointer to a class
5245 * Returns: @obj if @obj is derived from @klass
5248 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5251 mono_class_init (klass);
5253 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5254 return mono_object_isinst_mbyref (obj, klass);
5259 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5263 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5272 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5273 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5277 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5278 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5281 MonoClass *oklass = vt->klass;
5282 if (mono_class_is_transparent_proxy (oklass))
5283 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5285 mono_class_setup_supertypes (klass);
5286 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5289 #ifndef DISABLE_REMOTING
5290 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5292 MonoDomain *domain = mono_domain_get ();
5294 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5295 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5296 MonoMethod *im = NULL;
5299 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5300 im = mono_object_get_virtual_method (rp, im);
5303 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5306 res = mono_runtime_invoke (im, rp, pa, NULL);
5308 if (*(MonoBoolean *) mono_object_unbox(res)) {
5309 /* Update the vtable of the remote type, so it can safely cast to this new type */
5310 mono_upgrade_remote_class (domain, obj, klass);
5314 #endif /* DISABLE_REMOTING */
5319 * mono_object_castclass_mbyref:
5321 * @klass: a pointer to a class
5323 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5326 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5328 if (!obj) return NULL;
5329 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5331 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5333 "InvalidCastException"));
5338 MonoDomain *orig_domain;
5344 str_lookup (MonoDomain *domain, gpointer user_data)
5346 LDStrInfo *info = user_data;
5347 if (info->res || domain == info->orig_domain)
5349 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5355 mono_string_get_pinned (MonoString *str)
5359 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5360 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5362 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5363 news->length = mono_string_length (str);
5369 #define mono_string_get_pinned(str) (str)
5373 mono_string_is_interned_lookup (MonoString *str, int insert)
5375 MonoGHashTable *ldstr_table;
5379 domain = ((MonoObject *)str)->vtable->domain;
5380 ldstr_table = domain->ldstr_table;
5382 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5387 str = mono_string_get_pinned (str);
5389 mono_g_hash_table_insert (ldstr_table, str, str);
5393 LDStrInfo ldstr_info;
5394 ldstr_info.orig_domain = domain;
5395 ldstr_info.ins = str;
5396 ldstr_info.res = NULL;
5398 mono_domain_foreach (str_lookup, &ldstr_info);
5399 if (ldstr_info.res) {
5401 * the string was already interned in some other domain:
5402 * intern it in the current one as well.
5404 mono_g_hash_table_insert (ldstr_table, str, str);
5414 * mono_string_is_interned:
5415 * @o: String to probe
5417 * Returns whether the string has been interned.
5420 mono_string_is_interned (MonoString *o)
5422 return mono_string_is_interned_lookup (o, FALSE);
5426 * mono_string_intern:
5427 * @o: String to intern
5429 * Interns the string passed.
5430 * Returns: The interned string.
5433 mono_string_intern (MonoString *str)
5435 return mono_string_is_interned_lookup (str, TRUE);
5440 * @domain: the domain where the string will be used.
5441 * @image: a metadata context
5442 * @idx: index into the user string table.
5444 * Implementation for the ldstr opcode.
5445 * Returns: a loaded string from the @image/@idx combination.
5448 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5450 MONO_ARCH_SAVE_REGS;
5452 if (image->dynamic) {
5453 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5456 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5457 return NULL; /*FIXME we should probably be raising an exception here*/
5458 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5463 * mono_ldstr_metadata_sig
5464 * @domain: the domain for the string
5465 * @sig: the signature of a metadata string
5467 * Returns: a MonoString for a string stored in the metadata
5470 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5472 const char *str = sig;
5473 MonoString *o, *interned;
5476 len2 = mono_metadata_decode_blob_size (str, &str);
5479 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5480 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5483 guint16 *p2 = (guint16*)mono_string_chars (o);
5484 for (i = 0; i < len2; ++i) {
5485 *p2 = GUINT16_FROM_LE (*p2);
5491 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5493 /* o will get garbage collected */
5497 o = mono_string_get_pinned (o);
5499 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5506 * mono_string_to_utf8:
5507 * @s: a System.String
5509 * Returns the UTF8 representation for @s.
5510 * The resulting buffer needs to be freed with mono_free().
5512 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5515 mono_string_to_utf8 (MonoString *s)
5518 char *result = mono_string_to_utf8_checked (s, &error);
5520 if (!mono_error_ok (&error))
5521 mono_error_raise_exception (&error);
5526 * mono_string_to_utf8_checked:
5527 * @s: a System.String
5528 * @error: a MonoError.
5530 * Converts a MonoString to its UTF8 representation. May fail; check
5531 * @error to determine whether the conversion was successful.
5532 * The resulting buffer should be freed with mono_free().
5535 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5539 GError *gerror = NULL;
5541 mono_error_init (error);
5547 return g_strdup ("");
5549 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5551 mono_error_set_argument (error, "string", "%s", gerror->message);
5552 g_error_free (gerror);
5555 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5556 if (s->length > written) {
5557 /* allocate the total length and copy the part of the string that has been converted */
5558 char *as2 = g_malloc0 (s->length);
5559 memcpy (as2, as, written);
5568 * mono_string_to_utf8_ignore:
5571 * Converts a MonoString to its UTF8 representation. Will ignore
5572 * invalid surrogate pairs.
5573 * The resulting buffer should be freed with mono_free().
5577 mono_string_to_utf8_ignore (MonoString *s)
5586 return g_strdup ("");
5588 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5590 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5591 if (s->length > written) {
5592 /* allocate the total length and copy the part of the string that has been converted */
5593 char *as2 = g_malloc0 (s->length);
5594 memcpy (as2, as, written);
5603 * mono_string_to_utf8_image_ignore:
5604 * @s: a System.String
5606 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5609 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5611 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5615 * mono_string_to_utf8_mp_ignore:
5616 * @s: a System.String
5618 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5621 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5623 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5628 * mono_string_to_utf16:
5631 * Return an null-terminated array of the utf-16 chars
5632 * contained in @s. The result must be freed with g_free().
5633 * This is a temporary helper until our string implementation
5634 * is reworked to always include the null terminating char.
5637 mono_string_to_utf16 (MonoString *s)
5644 as = g_malloc ((s->length * 2) + 2);
5645 as [(s->length * 2)] = '\0';
5646 as [(s->length * 2) + 1] = '\0';
5649 return (gunichar2 *)(as);
5652 memcpy (as, mono_string_chars(s), s->length * 2);
5653 return (gunichar2 *)(as);
5657 * mono_string_from_utf16:
5658 * @data: the UTF16 string (LPWSTR) to convert
5660 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5662 * Returns: a MonoString.
5665 mono_string_from_utf16 (gunichar2 *data)
5667 MonoDomain *domain = mono_domain_get ();
5673 while (data [len]) len++;
5675 return mono_string_new_utf16 (domain, data, len);
5680 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5687 r = mono_string_to_utf8_ignore (s);
5689 r = mono_string_to_utf8_checked (s, error);
5690 if (!mono_error_ok (error))
5697 len = strlen (r) + 1;
5699 mp_s = mono_mempool_alloc (mp, len);
5701 mp_s = mono_image_alloc (image, len);
5703 memcpy (mp_s, r, len);
5711 * mono_string_to_utf8_image:
5712 * @s: a System.String
5714 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5717 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5719 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5723 * mono_string_to_utf8_mp:
5724 * @s: a System.String
5726 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5729 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5731 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5735 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5738 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5740 eh_callbacks = *cbs;
5743 MonoRuntimeExceptionHandlingCallbacks *
5744 mono_get_eh_callbacks (void)
5746 return &eh_callbacks;
5750 * mono_raise_exception:
5751 * @ex: exception object
5753 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5756 mono_raise_exception (MonoException *ex)
5759 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5760 * that will cause gcc to omit the function epilog, causing problems when
5761 * the JIT tries to walk the stack, since the return address on the stack
5762 * will point into the next function in the executable, not this one.
5764 eh_callbacks.mono_raise_exception (ex);
5768 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5770 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5774 * mono_wait_handle_new:
5775 * @domain: Domain where the object will be created
5776 * @handle: Handle for the wait handle
5778 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5781 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5783 MonoWaitHandle *res;
5784 gpointer params [1];
5785 static MonoMethod *handle_set;
5787 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5789 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5791 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5793 params [0] = &handle;
5794 mono_runtime_invoke (handle_set, res, params, NULL);
5800 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5802 static MonoClassField *f_os_handle;
5803 static MonoClassField *f_safe_handle;
5805 if (!f_os_handle && !f_safe_handle) {
5806 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5807 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5812 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5816 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5823 mono_runtime_capture_context (MonoDomain *domain)
5825 RuntimeInvokeFunction runtime_invoke;
5827 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5828 MonoMethod *method = mono_get_context_capture_method ();
5829 MonoMethod *wrapper;
5832 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5833 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5834 domain->capture_context_method = mono_compile_method (method);
5837 runtime_invoke = domain->capture_context_runtime_invoke;
5839 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5842 * mono_async_result_new:
5843 * @domain:domain where the object will be created.
5844 * @handle: wait handle.
5845 * @state: state to pass to AsyncResult
5846 * @data: C closure data.
5848 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5849 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5853 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5855 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5856 MonoObject *context = mono_runtime_capture_context (domain);
5857 /* we must capture the execution context from the original thread */
5859 MONO_OBJECT_SETREF (res, execution_context, context);
5860 /* note: result may be null if the flow is suppressed */
5864 MONO_OBJECT_SETREF (res, object_data, object_data);
5865 MONO_OBJECT_SETREF (res, async_state, state);
5867 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5869 res->sync_completed = FALSE;
5870 res->completed = FALSE;
5876 mono_message_init (MonoDomain *domain,
5877 MonoMethodMessage *this,
5878 MonoReflectionMethod *method,
5879 MonoArray *out_args)
5881 static MonoClass *object_array_klass;
5882 static MonoClass *byte_array_klass;
5883 static MonoClass *string_array_klass;
5884 MonoMethodSignature *sig = mono_method_signature (method->method);
5890 if (!object_array_klass) {
5893 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5895 byte_array_klass = klass;
5897 klass = mono_array_class_get (mono_defaults.string_class, 1);
5899 string_array_klass = klass;
5901 klass = mono_array_class_get (mono_defaults.object_class, 1);
5904 mono_atomic_store_release (&object_array_klass, klass);
5907 MONO_OBJECT_SETREF (this, method, method);
5909 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5910 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5911 this->async_result = NULL;
5912 this->call_type = CallType_Sync;
5914 names = g_new (char *, sig->param_count);
5915 mono_method_get_param_names (method->method, (const char **) names);
5916 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5918 for (i = 0; i < sig->param_count; i++) {
5919 name = mono_string_new (domain, names [i]);
5920 mono_array_setref (this->names, i, name);
5924 for (i = 0, j = 0; i < sig->param_count; i++) {
5925 if (sig->params [i]->byref) {
5927 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5928 mono_array_setref (this->args, i, arg);
5932 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5936 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5939 mono_array_set (this->arg_types, guint8, i, arg_type);
5943 #ifndef DISABLE_REMOTING
5945 * mono_remoting_invoke:
5946 * @real_proxy: pointer to a RealProxy object
5947 * @msg: The MonoMethodMessage to execute
5948 * @exc: used to store exceptions
5949 * @out_args: used to store output arguments
5951 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5952 * IMessage interface and it is not trivial to extract results from there. So
5953 * we call an helper method PrivateInvoke instead of calling
5954 * RealProxy::Invoke() directly.
5956 * Returns: the result object.
5959 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5960 MonoObject **exc, MonoArray **out_args)
5962 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5965 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5968 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5970 real_proxy->vtable->domain->private_invoke_method = im;
5973 pa [0] = real_proxy;
5978 return mono_runtime_invoke (im, NULL, pa, exc);
5983 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5984 MonoObject **exc, MonoArray **out_args)
5986 static MonoClass *object_array_klass;
5989 MonoMethodSignature *sig;
5991 int i, j, outarg_count = 0;
5993 #ifndef DISABLE_REMOTING
5994 if (target && mono_object_is_transparent_proxy (target)) {
5995 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5996 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
5997 target = tp->rp->unwrapped_server;
5999 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6004 domain = mono_domain_get ();
6005 method = msg->method->method;
6006 sig = mono_method_signature (method);
6008 for (i = 0; i < sig->param_count; i++) {
6009 if (sig->params [i]->byref)
6013 if (!object_array_klass) {
6016 klass = mono_array_class_get (mono_defaults.object_class, 1);
6019 mono_memory_barrier ();
6020 object_array_klass = klass;
6023 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6024 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6027 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6029 for (i = 0, j = 0; i < sig->param_count; i++) {
6030 if (sig->params [i]->byref) {
6032 arg = mono_array_get (msg->args, gpointer, i);
6033 mono_array_setref (*out_args, j, arg);
6042 * mono_object_to_string:
6044 * @exc: Any exception thrown by ToString (). May be NULL.
6046 * Returns: the result of calling ToString () on an object.
6049 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6051 static MonoMethod *to_string = NULL;
6058 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6060 method = mono_object_get_virtual_method (obj, to_string);
6062 // Unbox value type if needed
6063 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6064 target = mono_object_unbox (obj);
6067 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6071 * mono_print_unhandled_exception:
6072 * @exc: The exception
6074 * Prints the unhandled exception.
6077 mono_print_unhandled_exception (MonoObject *exc)
6080 char *message = (char*)"";
6081 gboolean free_message = FALSE;
6084 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6085 message = g_strdup ("OutOfMemoryException");
6086 free_message = TRUE;
6089 if (((MonoException*)exc)->native_trace_ips) {
6090 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6091 free_message = TRUE;
6093 MonoObject *other_exc = NULL;
6094 str = mono_object_to_string (exc, &other_exc);
6096 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6097 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6099 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6100 original_backtrace, nested_backtrace);
6102 g_free (original_backtrace);
6103 g_free (nested_backtrace);
6104 free_message = TRUE;
6106 message = mono_string_to_utf8_checked (str, &error);
6107 if (!mono_error_ok (&error)) {
6108 mono_error_cleanup (&error);
6109 message = (char *) "";
6111 free_message = TRUE;
6118 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6119 * exc->vtable->klass->name, message);
6121 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6128 * mono_delegate_ctor:
6129 * @this: pointer to an uninitialized delegate object
6130 * @target: target object
6131 * @addr: pointer to native code
6134 * Initialize a delegate and sets a specific method, not the one
6135 * associated with addr. This is useful when sharing generic code.
6136 * In that case addr will most probably not be associated with the
6137 * correct instantiation of the method.
6140 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6142 MonoDelegate *delegate = (MonoDelegate *)this;
6149 delegate->method = method;
6151 class = this->vtable->klass;
6152 mono_stats.delegate_creations++;
6154 #ifndef DISABLE_REMOTING
6155 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6157 method = mono_marshal_get_remoting_invoke (method);
6158 delegate->method_ptr = mono_compile_method (method);
6159 MONO_OBJECT_SETREF (delegate, target, target);
6163 delegate->method_ptr = addr;
6164 MONO_OBJECT_SETREF (delegate, target, target);
6167 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6171 * mono_delegate_ctor:
6172 * @this: pointer to an uninitialized delegate object
6173 * @target: target object
6174 * @addr: pointer to native code
6176 * This is used to initialize a delegate.
6179 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6181 MonoDomain *domain = mono_domain_get ();
6183 MonoMethod *method = NULL;
6187 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6189 if (!ji && domain != mono_get_root_domain ())
6190 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6192 method = mono_jit_info_get_method (ji);
6193 g_assert (!method->klass->generic_container);
6196 mono_delegate_ctor_with_method (this, target, addr, method);
6200 * mono_method_call_message_new:
6201 * @method: method to encapsulate
6202 * @params: parameters to the method
6203 * @invoke: optional, delegate invoke.
6204 * @cb: async callback delegate.
6205 * @state: state passed to the async callback.
6207 * Translates arguments pointers into a MonoMethodMessage.
6210 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6211 MonoDelegate **cb, MonoObject **state)
6213 MonoDomain *domain = mono_domain_get ();
6214 MonoMethodSignature *sig = mono_method_signature (method);
6215 MonoMethodMessage *msg;
6218 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6221 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6222 count = sig->param_count - 2;
6224 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6225 count = sig->param_count;
6228 for (i = 0; i < count; i++) {
6233 if (sig->params [i]->byref)
6234 vpos = *((gpointer *)params [i]);
6238 type = sig->params [i]->type;
6239 class = mono_class_from_mono_type (sig->params [i]);
6241 if (class->valuetype)
6242 arg = mono_value_box (domain, class, vpos);
6244 arg = *((MonoObject **)vpos);
6246 mono_array_setref (msg->args, i, arg);
6249 if (cb != NULL && state != NULL) {
6250 *cb = *((MonoDelegate **)params [i]);
6252 *state = *((MonoObject **)params [i]);
6259 * mono_method_return_message_restore:
6261 * Restore results from message based processing back to arguments pointers
6264 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6266 MonoMethodSignature *sig = mono_method_signature (method);
6267 int i, j, type, size, out_len;
6269 if (out_args == NULL)
6271 out_len = mono_array_length (out_args);
6275 for (i = 0, j = 0; i < sig->param_count; i++) {
6276 MonoType *pt = sig->params [i];
6281 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6283 arg = mono_array_get (out_args, gpointer, j);
6286 g_assert (type != MONO_TYPE_VOID);
6288 if (MONO_TYPE_IS_REFERENCE (pt)) {
6289 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6292 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6293 size = mono_class_value_size (class, NULL);
6294 if (class->has_references)
6295 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6297 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6299 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6300 mono_gc_bzero (*((gpointer *)params [i]), size);
6309 #ifndef DISABLE_REMOTING
6312 * mono_load_remote_field:
6313 * @this: pointer to an object
6314 * @klass: klass of the object containing @field
6315 * @field: the field to load
6316 * @res: a storage to store the result
6318 * This method is called by the runtime on attempts to load fields of
6319 * transparent proxy objects. @this points to such TP, @klass is the class of
6320 * the object containing @field. @res is a storage location which can be
6321 * used to store the result.
6323 * Returns: an address pointing to the value of field.
6326 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6328 static MonoMethod *getter = NULL;
6329 MonoDomain *domain = mono_domain_get ();
6330 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6331 MonoClass *field_class;
6332 MonoMethodMessage *msg;
6333 MonoArray *out_args;
6337 g_assert (mono_object_is_transparent_proxy (this));
6338 g_assert (res != NULL);
6340 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6341 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6346 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6350 field_class = mono_class_from_mono_type (field->type);
6352 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6353 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6354 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6356 full_name = mono_type_get_full_name (klass);
6357 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6358 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6361 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6363 if (exc) mono_raise_exception ((MonoException *)exc);
6365 if (mono_array_length (out_args) == 0)
6368 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6370 if (field_class->valuetype) {
6371 return ((char *)*res) + sizeof (MonoObject);
6377 * mono_load_remote_field_new:
6382 * Missing documentation.
6385 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6387 static MonoMethod *getter = NULL;
6388 MonoDomain *domain = mono_domain_get ();
6389 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6390 MonoClass *field_class;
6391 MonoMethodMessage *msg;
6392 MonoArray *out_args;
6393 MonoObject *exc, *res;
6396 g_assert (mono_object_is_transparent_proxy (this));
6398 field_class = mono_class_from_mono_type (field->type);
6400 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6402 if (field_class->valuetype) {
6403 res = mono_object_new (domain, field_class);
6404 val = ((gchar *) res) + sizeof (MonoObject);
6408 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6413 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6417 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6418 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6420 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6422 full_name = mono_type_get_full_name (klass);
6423 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6424 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6427 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6429 if (exc) mono_raise_exception ((MonoException *)exc);
6431 if (mono_array_length (out_args) == 0)
6434 res = mono_array_get (out_args, MonoObject *, 0);
6440 * mono_store_remote_field:
6441 * @this: pointer to an object
6442 * @klass: klass of the object containing @field
6443 * @field: the field to load
6444 * @val: the value/object to store
6446 * This method is called by the runtime on attempts to store fields of
6447 * transparent proxy objects. @this points to such TP, @klass is the class of
6448 * the object containing @field. @val is the new value to store in @field.
6451 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6453 static MonoMethod *setter = NULL;
6454 MonoDomain *domain = mono_domain_get ();
6455 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6456 MonoClass *field_class;
6457 MonoMethodMessage *msg;
6458 MonoArray *out_args;
6463 g_assert (mono_object_is_transparent_proxy (this));
6465 field_class = mono_class_from_mono_type (field->type);
6467 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6468 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6469 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6474 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6478 if (field_class->valuetype)
6479 arg = mono_value_box (domain, field_class, val);
6481 arg = *((MonoObject **)val);
6484 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6485 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6487 full_name = mono_type_get_full_name (klass);
6488 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6489 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6490 mono_array_setref (msg->args, 2, arg);
6493 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6495 if (exc) mono_raise_exception ((MonoException *)exc);
6499 * mono_store_remote_field_new:
6505 * Missing documentation
6508 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6510 static MonoMethod *setter = NULL;
6511 MonoDomain *domain = mono_domain_get ();
6512 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6513 MonoClass *field_class;
6514 MonoMethodMessage *msg;
6515 MonoArray *out_args;
6519 g_assert (mono_object_is_transparent_proxy (this));
6521 field_class = mono_class_from_mono_type (field->type);
6523 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6524 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6525 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6530 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6534 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6535 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6537 full_name = mono_type_get_full_name (klass);
6538 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6539 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6540 mono_array_setref (msg->args, 2, arg);
6543 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6545 if (exc) mono_raise_exception ((MonoException *)exc);
6550 * mono_create_ftnptr:
6552 * Given a function address, create a function descriptor for it.
6553 * This is only needed on some platforms.
6556 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6558 return callbacks.create_ftnptr (domain, addr);
6562 * mono_get_addr_from_ftnptr:
6564 * Given a pointer to a function descriptor, return the function address.
6565 * This is only needed on some platforms.
6568 mono_get_addr_from_ftnptr (gpointer descr)
6570 return callbacks.get_addr_from_ftnptr (descr);
6574 * mono_string_chars:
6577 * Returns a pointer to the UCS16 characters stored in the MonoString
6580 mono_string_chars (MonoString *s)
6586 * mono_string_length:
6589 * Returns the lenght in characters of the string
6592 mono_string_length (MonoString *s)
6598 * mono_array_length:
6599 * @array: a MonoArray*
6601 * Returns the total number of elements in the array. This works for
6602 * both vectors and multidimensional arrays.
6605 mono_array_length (MonoArray *array)
6607 return array->max_length;
6611 * mono_array_addr_with_size:
6612 * @array: a MonoArray*
6613 * @size: size of the array elements
6614 * @idx: index into the array
6616 * Returns the address of the @idx element in the array.
6619 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6621 return ((char*)(array)->vector) + size * idx;