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 ();
489 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
491 g_error ("remoting not installed");
496 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
498 g_assert_not_reached ();
502 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
503 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
504 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
505 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
506 static MonoImtThunkBuilder imt_thunk_builder = NULL;
507 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
508 #if (MONO_IMT_SIZE > 32)
509 #error "MONO_IMT_SIZE cannot be larger than 32"
513 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
515 memcpy (&callbacks, cbs, sizeof (*cbs));
518 MonoRuntimeCallbacks*
519 mono_get_runtime_callbacks (void)
525 mono_install_trampoline (MonoTrampoline func)
527 arch_create_jit_trampoline = func? func: default_trampoline;
531 mono_install_jump_trampoline (MonoJumpTrampoline func)
533 arch_create_jump_trampoline = func? func: default_jump_trampoline;
537 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
539 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
543 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
545 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
549 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
550 imt_thunk_builder = func;
553 static MonoCompileFunc default_mono_compile_method = NULL;
556 * mono_install_compile_method:
557 * @func: function to install
559 * This is a VM internal routine
562 mono_install_compile_method (MonoCompileFunc func)
564 default_mono_compile_method = func;
568 * mono_compile_method:
569 * @method: The method to compile.
571 * This JIT-compiles the method, and returns the pointer to the native code
575 mono_compile_method (MonoMethod *method)
577 if (!default_mono_compile_method) {
578 g_error ("compile method called on uninitialized runtime");
581 return default_mono_compile_method (method);
585 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
587 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
591 mono_runtime_create_delegate_trampoline (MonoClass *klass)
593 return arch_create_delegate_trampoline (mono_domain_get (), klass);
596 static MonoFreeMethodFunc default_mono_free_method = NULL;
599 * mono_install_free_method:
600 * @func: pointer to the MonoFreeMethodFunc used to release a method
602 * This is an internal VM routine, it is used for the engines to
603 * register a handler to release the resources associated with a method.
605 * Methods are freed when no more references to the delegate that holds
609 mono_install_free_method (MonoFreeMethodFunc func)
611 default_mono_free_method = func;
615 * mono_runtime_free_method:
616 * @domain; domain where the method is hosted
617 * @method: method to release
619 * This routine is invoked to free the resources associated with
620 * a method that has been JIT compiled. This is used to discard
621 * methods that were used only temporarily (for example, used in marshalling)
625 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
627 if (default_mono_free_method != NULL)
628 default_mono_free_method (domain, method);
630 mono_method_clear_object (domain, method);
632 mono_free_method (method);
636 * The vtables in the root appdomain are assumed to be reachable by other
637 * roots, and we don't use typed allocation in the other domains.
640 /* The sync block is no longer a GC pointer */
641 #define GC_HEADER_BITMAP (0)
643 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
646 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
648 MonoClassField *field;
654 max_size = mono_class_data_size (class) / sizeof (gpointer);
656 max_size = class->instance_size / sizeof (gpointer);
657 if (max_size > size) {
658 g_assert (offset <= 0);
659 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
664 /*An Ephemeron cannot be marked by sgen*/
665 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
667 memset (bitmap, 0, size / 8);
672 for (p = class; p != NULL; p = p->parent) {
673 gpointer iter = NULL;
674 while ((field = mono_class_get_fields (p, &iter))) {
678 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
680 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
683 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
686 /* FIXME: should not happen, flag as type load error */
687 if (field->type->byref)
690 if (static_fields && field->offset == -1)
694 pos = field->offset / sizeof (gpointer);
697 type = mono_type_get_underlying_type (field->type);
698 switch (type->type) {
701 case MONO_TYPE_FNPTR:
703 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
708 if (class->image != mono_defaults.corlib)
711 case MONO_TYPE_STRING:
712 case MONO_TYPE_SZARRAY:
713 case MONO_TYPE_CLASS:
714 case MONO_TYPE_OBJECT:
715 case MONO_TYPE_ARRAY:
716 g_assert ((field->offset % sizeof(gpointer)) == 0);
718 g_assert (pos < size || pos <= max_size);
719 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
720 *max_set = MAX (*max_set, pos);
722 case MONO_TYPE_GENERICINST:
723 if (!mono_type_generic_inst_is_valuetype (type)) {
724 g_assert ((field->offset % sizeof(gpointer)) == 0);
726 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
727 *max_set = MAX (*max_set, pos);
732 case MONO_TYPE_VALUETYPE: {
733 MonoClass *fclass = mono_class_from_mono_type (field->type);
734 if (fclass->has_references) {
735 /* remove the object header */
736 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
750 case MONO_TYPE_BOOLEAN:
754 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
765 * mono_class_compute_bitmap:
767 * Mono internal function to compute a bitmap of reference fields in a class.
770 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
772 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
777 * similar to the above, but sets the bits in the bitmap for any non-ref field
778 * and ignores static fields
781 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
783 MonoClassField *field;
788 max_size = class->instance_size / sizeof (gpointer);
789 if (max_size >= size) {
790 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
793 for (p = class; p != NULL; p = p->parent) {
794 gpointer iter = NULL;
795 while ((field = mono_class_get_fields (p, &iter))) {
798 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
800 /* FIXME: should not happen, flag as type load error */
801 if (field->type->byref)
804 pos = field->offset / sizeof (gpointer);
807 type = mono_type_get_underlying_type (field->type);
808 switch (type->type) {
809 #if SIZEOF_VOID_P == 8
813 case MONO_TYPE_FNPTR:
818 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
819 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
820 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
823 #if SIZEOF_VOID_P == 4
827 case MONO_TYPE_FNPTR:
832 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
833 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
834 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
840 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
841 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
842 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
845 case MONO_TYPE_BOOLEAN:
848 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
850 case MONO_TYPE_STRING:
851 case MONO_TYPE_SZARRAY:
852 case MONO_TYPE_CLASS:
853 case MONO_TYPE_OBJECT:
854 case MONO_TYPE_ARRAY:
856 case MONO_TYPE_GENERICINST:
857 if (!mono_type_generic_inst_is_valuetype (type)) {
862 case MONO_TYPE_VALUETYPE: {
863 MonoClass *fclass = mono_class_from_mono_type (field->type);
864 /* remove the object header */
865 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
869 g_assert_not_reached ();
878 * mono_class_insecure_overlapping:
879 * check if a class with explicit layout has references and non-references
880 * fields overlapping.
882 * Returns: TRUE if it is insecure to load the type.
885 mono_class_insecure_overlapping (MonoClass *klass)
889 gsize default_bitmap [4] = {0};
891 gsize default_nrbitmap [4] = {0};
892 int i, insecure = FALSE;
895 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
896 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
898 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
899 int idx = i % (sizeof (bitmap [0]) * 8);
900 if (bitmap [idx] & nrbitmap [idx]) {
905 if (bitmap != default_bitmap)
907 if (nrbitmap != default_nrbitmap)
910 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
918 mono_string_alloc (int length)
920 return mono_string_new_size (mono_domain_get (), length);
924 mono_class_compute_gc_descriptor (MonoClass *class)
928 gsize default_bitmap [4] = {0};
929 static gboolean gcj_inited = FALSE;
934 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
935 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
936 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
937 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
939 #ifdef HAVE_GC_GCJ_MALLOC
941 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
945 #ifdef GC_REDIRECT_TO_LOCAL
946 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
947 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
949 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
950 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
955 mono_loader_unlock ();
959 mono_class_init (class);
961 if (class->gc_descr_inited)
964 class->gc_descr_inited = TRUE;
965 class->gc_descr = GC_NO_DESCRIPTOR;
967 bitmap = default_bitmap;
968 if (class == mono_defaults.string_class) {
969 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
970 } else if (class->rank) {
971 mono_class_compute_gc_descriptor (class->element_class);
972 if (!class->element_class->valuetype) {
974 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
975 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
976 class->name_space, class->name);*/
978 /* remove the object header */
979 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
980 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));
981 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
982 class->name_space, class->name);*/
983 if (bitmap != default_bitmap)
987 /*static int count = 0;
990 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
991 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
993 if (class->gc_descr == GC_NO_DESCRIPTOR)
994 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
996 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
997 if (bitmap != default_bitmap)
1003 * field_is_special_static:
1004 * @fklass: The MonoClass to look up.
1005 * @field: The MonoClassField describing the field.
1007 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1008 * SPECIAL_STATIC_NONE otherwise.
1011 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1013 MonoCustomAttrInfo *ainfo;
1015 ainfo = mono_custom_attrs_from_field (fklass, field);
1018 for (i = 0; i < ainfo->num_attrs; ++i) {
1019 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1020 if (klass->image == mono_defaults.corlib) {
1021 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1022 mono_custom_attrs_free (ainfo);
1023 return SPECIAL_STATIC_THREAD;
1025 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1026 mono_custom_attrs_free (ainfo);
1027 return SPECIAL_STATIC_CONTEXT;
1031 mono_custom_attrs_free (ainfo);
1032 return SPECIAL_STATIC_NONE;
1035 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1036 #define mix(a,b,c) { \
1037 a -= c; a ^= rot(c, 4); c += b; \
1038 b -= a; b ^= rot(a, 6); a += c; \
1039 c -= b; c ^= rot(b, 8); b += a; \
1040 a -= c; a ^= rot(c,16); c += b; \
1041 b -= a; b ^= rot(a,19); a += c; \
1042 c -= b; c ^= rot(b, 4); b += a; \
1044 #define final(a,b,c) { \
1045 c ^= b; c -= rot(b,14); \
1046 a ^= c; a -= rot(c,11); \
1047 b ^= a; b -= rot(a,25); \
1048 c ^= b; c -= rot(b,16); \
1049 a ^= c; a -= rot(c,4); \
1050 b ^= a; b -= rot(a,14); \
1051 c ^= b; c -= rot(b,24); \
1055 * mono_method_get_imt_slot:
1057 * The IMT slot is embedded into AOTed code, so this must return the same value
1058 * for the same method across all executions. This means:
1059 * - pointers shouldn't be used as hash values.
1060 * - mono_metadata_str_hash () should be used for hashing strings.
1063 mono_method_get_imt_slot (MonoMethod *method)
1065 MonoMethodSignature *sig;
1067 guint32 *hashes_start, *hashes;
1071 /* This can be used to stress tests the collision code */
1075 * We do this to simplify generic sharing. It will hurt
1076 * performance in cases where a class implements two different
1077 * instantiations of the same generic interface.
1078 * The code in build_imt_slots () depends on this.
1080 if (method->is_inflated)
1081 method = ((MonoMethodInflated*)method)->declaring;
1083 sig = mono_method_signature (method);
1084 hashes_count = sig->param_count + 4;
1085 hashes_start = malloc (hashes_count * sizeof (guint32));
1086 hashes = hashes_start;
1088 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1089 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1090 method->klass->name_space, method->klass->name, method->name);
1093 /* Initialize hashes */
1094 hashes [0] = mono_metadata_str_hash (method->klass->name);
1095 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1096 hashes [2] = mono_metadata_str_hash (method->name);
1097 hashes [3] = mono_metadata_type_hash (sig->ret);
1098 for (i = 0; i < sig->param_count; i++) {
1099 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1102 /* Setup internal state */
1103 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1105 /* Handle most of the hashes */
1106 while (hashes_count > 3) {
1115 /* Handle the last 3 hashes (all the case statements fall through) */
1116 switch (hashes_count) {
1117 case 3 : c += hashes [2];
1118 case 2 : b += hashes [1];
1119 case 1 : a += hashes [0];
1121 case 0: /* nothing left to add */
1125 free (hashes_start);
1126 /* Report the result */
1127 return c % MONO_IMT_SIZE;
1136 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1137 guint32 imt_slot = mono_method_get_imt_slot (method);
1138 MonoImtBuilderEntry *entry;
1140 if (slot_num >= 0 && imt_slot != slot_num) {
1141 /* we build just a single imt slot and this is not it */
1145 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1146 entry->key = method;
1147 entry->value.vtable_slot = vtable_slot;
1148 entry->next = imt_builder [imt_slot];
1149 if (imt_builder [imt_slot] != NULL) {
1150 entry->children = imt_builder [imt_slot]->children + 1;
1151 if (entry->children == 1) {
1152 mono_stats.imt_slots_with_collisions++;
1153 *imt_collisions_bitmap |= (1 << imt_slot);
1156 entry->children = 0;
1157 mono_stats.imt_used_slots++;
1159 imt_builder [imt_slot] = entry;
1162 char *method_name = mono_method_full_name (method, TRUE);
1163 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1164 method, method_name, imt_slot, vtable_slot, entry->children);
1165 g_free (method_name);
1172 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1174 MonoMethod *method = e->key;
1175 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1179 method->klass->name_space,
1180 method->klass->name,
1183 printf (" * %s: NULL\n", message);
1189 compare_imt_builder_entries (const void *p1, const void *p2) {
1190 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1191 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1193 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1197 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1199 int count = end - start;
1200 int chunk_start = out_array->len;
1203 for (i = start; i < end; ++i) {
1204 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1205 item->key = sorted_array [i]->key;
1206 item->value = sorted_array [i]->value;
1207 item->has_target_code = sorted_array [i]->has_target_code;
1208 item->is_equals = TRUE;
1210 item->check_target_idx = out_array->len + 1;
1212 item->check_target_idx = 0;
1213 g_ptr_array_add (out_array, item);
1216 int middle = start + count / 2;
1217 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1219 item->key = sorted_array [middle]->key;
1220 item->is_equals = FALSE;
1221 g_ptr_array_add (out_array, item);
1222 imt_emit_ir (sorted_array, start, middle, out_array);
1223 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1229 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1230 int number_of_entries = entries->children + 1;
1231 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1232 GPtrArray *result = g_ptr_array_new ();
1233 MonoImtBuilderEntry *current_entry;
1236 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1237 sorted_array [i] = current_entry;
1239 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1241 /*for (i = 0; i < number_of_entries; i++) {
1242 print_imt_entry (" sorted array:", sorted_array [i], i);
1245 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1247 free (sorted_array);
1252 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1254 if (imt_builder_entry != NULL) {
1255 if (imt_builder_entry->children == 0 && !fail_tramp) {
1256 /* No collision, return the vtable slot contents */
1257 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1259 /* Collision, build the thunk */
1260 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1263 result = imt_thunk_builder (vtable, domain,
1264 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1265 for (i = 0; i < imt_ir->len; ++i)
1266 g_free (g_ptr_array_index (imt_ir, i));
1267 g_ptr_array_free (imt_ir, TRUE);
1279 static MonoImtBuilderEntry*
1280 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1283 * LOCKING: requires the loader and domain locks.
1287 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1291 guint32 imt_collisions_bitmap = 0;
1292 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1293 int method_count = 0;
1294 gboolean record_method_count_for_max_collisions = FALSE;
1295 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1298 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1300 for (i = 0; i < klass->interface_offsets_count; ++i) {
1301 MonoClass *iface = klass->interfaces_packed [i];
1302 int interface_offset = klass->interface_offsets_packed [i];
1303 int method_slot_in_interface, vt_slot;
1305 if (mono_class_has_variant_generic_params (iface))
1306 has_variant_iface = TRUE;
1308 vt_slot = interface_offset;
1309 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1312 if (slot_num >= 0 && iface->is_inflated) {
1314 * The imt slot of the method is the same as for its declaring method,
1315 * see the comment in mono_method_get_imt_slot (), so we can
1316 * avoid inflating methods which will be discarded by
1317 * add_imt_builder_entry anyway.
1319 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1320 if (mono_method_get_imt_slot (method) != slot_num) {
1325 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1326 if (method->is_generic) {
1327 has_generic_virtual = TRUE;
1332 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1333 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1338 if (extra_interfaces) {
1339 int interface_offset = klass->vtable_size;
1341 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1342 MonoClass* iface = list_item->data;
1343 int method_slot_in_interface;
1344 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1345 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1346 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1348 interface_offset += iface->method.count;
1351 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1352 /* overwrite the imt slot only if we're building all the entries or if
1353 * we're building this specific one
1355 if (slot_num < 0 || i == slot_num) {
1356 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1359 if (imt_builder [i]) {
1360 MonoImtBuilderEntry *entry;
1362 /* Link entries with imt_builder [i] */
1363 for (entry = entries; entry->next; entry = entry->next) {
1365 MonoMethod *method = (MonoMethod*)entry->key;
1366 char *method_name = mono_method_full_name (method, TRUE);
1367 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1368 g_free (method_name);
1371 entry->next = imt_builder [i];
1372 entries->children += imt_builder [i]->children + 1;
1374 imt_builder [i] = entries;
1377 if (has_generic_virtual || has_variant_iface) {
1379 * There might be collisions later when the the thunk is expanded.
1381 imt_collisions_bitmap |= (1 << i);
1384 * The IMT thunk might be called with an instance of one of the
1385 * generic virtual methods, so has to fallback to the IMT trampoline.
1387 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1389 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1392 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1396 if (imt_builder [i] != NULL) {
1397 int methods_in_slot = imt_builder [i]->children + 1;
1398 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1399 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1400 record_method_count_for_max_collisions = TRUE;
1402 method_count += methods_in_slot;
1406 mono_stats.imt_number_of_methods += method_count;
1407 if (record_method_count_for_max_collisions) {
1408 mono_stats.imt_method_count_when_max_collisions = method_count;
1411 for (i = 0; i < MONO_IMT_SIZE; i++) {
1412 MonoImtBuilderEntry* entry = imt_builder [i];
1413 while (entry != NULL) {
1414 MonoImtBuilderEntry* next = entry->next;
1420 /* we OR the bitmap since we may build just a single imt slot at a time */
1421 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1425 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1426 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1430 * mono_vtable_build_imt_slot:
1431 * @vtable: virtual object table struct
1432 * @imt_slot: slot in the IMT table
1434 * Fill the given @imt_slot in the IMT table of @vtable with
1435 * a trampoline or a thunk for the case of collisions.
1436 * This is part of the internal mono API.
1438 * LOCKING: Take the domain lock.
1441 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1443 gpointer *imt = (gpointer*)vtable;
1444 imt -= MONO_IMT_SIZE;
1445 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1447 /* no support for extra interfaces: the proxy objects will need
1448 * to build the complete IMT
1449 * Update and heck needs to ahppen inside the proper domain lock, as all
1450 * the changes made to a MonoVTable.
1452 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1453 mono_domain_lock (vtable->domain);
1454 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1455 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1456 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1457 mono_domain_unlock (vtable->domain);
1458 mono_loader_unlock ();
1463 * The first two free list entries both belong to the wait list: The
1464 * first entry is the pointer to the head of the list and the second
1465 * entry points to the last element. That way appending and removing
1466 * the first element are both O(1) operations.
1468 #ifdef MONO_SMALL_CONFIG
1469 #define NUM_FREE_LISTS 6
1471 #define NUM_FREE_LISTS 12
1473 #define FIRST_FREE_LIST_SIZE 64
1474 #define MAX_WAIT_LENGTH 50
1475 #define THUNK_THRESHOLD 10
1478 * LOCKING: The domain lock must be held.
1481 init_thunk_free_lists (MonoDomain *domain)
1483 if (domain->thunk_free_lists)
1485 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1489 list_index_for_size (int item_size)
1492 int size = FIRST_FREE_LIST_SIZE;
1494 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1503 * mono_method_alloc_generic_virtual_thunk:
1505 * @size: size in bytes
1507 * Allocs size bytes to be used for the code of a generic virtual
1508 * thunk. It's either allocated from the domain's code manager or
1509 * reused from a previously invalidated piece.
1511 * LOCKING: The domain lock must be held.
1514 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1516 static gboolean inited = FALSE;
1517 static int generic_virtual_thunks_size = 0;
1521 MonoThunkFreeList **l;
1523 init_thunk_free_lists (domain);
1525 size += sizeof (guint32);
1526 if (size < sizeof (MonoThunkFreeList))
1527 size = sizeof (MonoThunkFreeList);
1529 i = list_index_for_size (size);
1530 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1531 if ((*l)->size >= size) {
1532 MonoThunkFreeList *item = *l;
1534 return ((guint32*)item) + 1;
1538 /* no suitable item found - search lists of larger sizes */
1539 while (++i < NUM_FREE_LISTS) {
1540 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1543 g_assert (item->size > size);
1544 domain->thunk_free_lists [i] = item->next;
1545 return ((guint32*)item) + 1;
1548 /* still nothing found - allocate it */
1550 mono_counters_register ("Generic virtual thunk bytes",
1551 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1554 generic_virtual_thunks_size += size;
1556 p = mono_domain_code_reserve (domain, size);
1559 mono_domain_lock (domain);
1560 if (!domain->generic_virtual_thunks)
1561 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1562 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1563 mono_domain_unlock (domain);
1569 * LOCKING: The domain lock must be held.
1572 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1575 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1576 gboolean found = FALSE;
1578 mono_domain_lock (domain);
1579 if (!domain->generic_virtual_thunks)
1580 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1581 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1583 mono_domain_unlock (domain);
1586 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1588 init_thunk_free_lists (domain);
1590 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1591 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1592 int length = item->length;
1595 /* unlink the first item from the wait list */
1596 domain->thunk_free_lists [0] = item->next;
1597 domain->thunk_free_lists [0]->length = length - 1;
1599 i = list_index_for_size (item->size);
1601 /* put it in the free list */
1602 item->next = domain->thunk_free_lists [i];
1603 domain->thunk_free_lists [i] = item;
1607 if (domain->thunk_free_lists [1]) {
1608 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1609 domain->thunk_free_lists [0]->length++;
1611 g_assert (!domain->thunk_free_lists [0]);
1613 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1614 domain->thunk_free_lists [0]->length = 1;
1618 typedef struct _GenericVirtualCase {
1622 struct _GenericVirtualCase *next;
1623 } GenericVirtualCase;
1626 * get_generic_virtual_entries:
1628 * Return IMT entries for the generic virtual method instances and
1629 * variant interface methods for vtable slot
1632 static MonoImtBuilderEntry*
1633 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1635 GenericVirtualCase *list;
1636 MonoImtBuilderEntry *entries;
1638 mono_domain_lock (domain);
1639 if (!domain->generic_virtual_cases)
1640 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1642 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1645 for (; list; list = list->next) {
1646 MonoImtBuilderEntry *entry;
1648 if (list->count < THUNK_THRESHOLD)
1651 entry = g_new0 (MonoImtBuilderEntry, 1);
1652 entry->key = list->method;
1653 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1654 entry->has_target_code = 1;
1656 entry->children = entries->children + 1;
1657 entry->next = entries;
1661 mono_domain_unlock (domain);
1663 /* FIXME: Leaking memory ? */
1668 * mono_method_add_generic_virtual_invocation:
1670 * @vtable_slot: pointer to the vtable slot
1671 * @method: the inflated generic virtual method
1672 * @code: the method's code
1674 * Registers a call via unmanaged code to a generic virtual method
1675 * instantiation or variant interface method. If the number of calls reaches a threshold
1676 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1677 * virtual method thunk.
1680 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1681 gpointer *vtable_slot,
1682 MonoMethod *method, gpointer code)
1684 static gboolean inited = FALSE;
1685 static int num_added = 0;
1687 GenericVirtualCase *gvc, *list;
1688 MonoImtBuilderEntry *entries;
1692 mono_domain_lock (domain);
1693 if (!domain->generic_virtual_cases)
1694 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1696 /* Check whether the case was already added */
1697 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1700 if (gvc->method == method)
1705 /* If not found, make a new one */
1707 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1708 gvc->method = method;
1711 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1713 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1716 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1722 if (++gvc->count == THUNK_THRESHOLD) {
1723 gpointer *old_thunk = *vtable_slot;
1724 gpointer vtable_trampoline = NULL;
1725 gpointer imt_trampoline = NULL;
1727 if ((gpointer)vtable_slot < (gpointer)vtable) {
1728 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1729 int imt_slot = MONO_IMT_SIZE + displacement;
1731 /* Force the rebuild of the thunk at the next call */
1732 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1733 *vtable_slot = imt_trampoline;
1735 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1737 entries = get_generic_virtual_entries (domain, vtable_slot);
1739 sorted = imt_sort_slot_entries (entries);
1741 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1745 MonoImtBuilderEntry *next = entries->next;
1750 for (i = 0; i < sorted->len; ++i)
1751 g_free (g_ptr_array_index (sorted, i));
1752 g_ptr_array_free (sorted, TRUE);
1755 #ifndef __native_client__
1756 /* We don't re-use any thunks as there is a lot of overhead */
1757 /* to deleting and re-using code in Native Client. */
1758 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1759 invalidate_generic_virtual_thunk (domain, old_thunk);
1763 mono_domain_unlock (domain);
1766 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1769 * mono_class_vtable:
1770 * @domain: the application domain
1771 * @class: the class to initialize
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1775 * On failure, NULL is returned, and class->exception_type is set.
1778 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1780 return mono_class_vtable_full (domain, class, FALSE);
1784 * mono_class_vtable_full:
1785 * @domain: the application domain
1786 * @class: the class to initialize
1787 * @raise_on_error if an exception should be raised on failure or not
1789 * VTables are domain specific because we create domain specific code, and
1790 * they contain the domain specific static class data.
1793 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1795 MonoClassRuntimeInfo *runtime_info;
1799 if (class->exception_type) {
1801 mono_raise_exception (mono_class_get_exception_for_failure (class));
1805 /* this check can be inlined in jitted code, too */
1806 runtime_info = class->runtime_info;
1807 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1808 return runtime_info->domain_vtables [domain->domain_id];
1809 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1813 * mono_class_try_get_vtable:
1814 * @domain: the application domain
1815 * @class: the class to initialize
1817 * This function tries to get the associated vtable from @class if
1818 * it was already created.
1821 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1823 MonoClassRuntimeInfo *runtime_info;
1827 runtime_info = class->runtime_info;
1828 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1829 return runtime_info->domain_vtables [domain->domain_id];
1834 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1837 MonoClassRuntimeInfo *runtime_info, *old_info;
1838 MonoClassField *field;
1840 int i, vtable_slots;
1841 int imt_table_bytes = 0;
1843 guint32 vtable_size, class_size;
1846 gpointer *interface_offsets;
1848 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1849 mono_domain_lock (domain);
1850 runtime_info = class->runtime_info;
1851 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1852 mono_domain_unlock (domain);
1853 mono_loader_unlock ();
1854 return runtime_info->domain_vtables [domain->domain_id];
1856 if (!class->inited || class->exception_type) {
1857 if (!mono_class_init (class) || class->exception_type) {
1858 mono_domain_unlock (domain);
1859 mono_loader_unlock ();
1861 mono_raise_exception (mono_class_get_exception_for_failure (class));
1866 /* Array types require that their element type be valid*/
1867 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1868 MonoClass *element_class = class->element_class;
1869 if (!element_class->inited)
1870 mono_class_init (element_class);
1872 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1873 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1874 mono_class_setup_vtable (element_class);
1876 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1877 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1878 if (class->exception_type == MONO_EXCEPTION_NONE)
1879 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1883 mono_raise_exception (mono_class_get_exception_for_failure (class));
1889 * For some classes, mono_class_init () already computed class->vtable_size, and
1890 * that is all that is needed because of the vtable trampolines.
1892 if (!class->vtable_size)
1893 mono_class_setup_vtable (class);
1895 if (class->generic_class && !class->vtable)
1896 mono_class_check_vtable_constraints (class, NULL);
1898 /* Initialize klass->has_finalize */
1899 mono_class_has_finalizer (class);
1901 if (class->exception_type) {
1902 mono_domain_unlock (domain);
1903 mono_loader_unlock ();
1905 mono_raise_exception (mono_class_get_exception_for_failure (class));
1909 vtable_slots = class->vtable_size;
1910 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1911 class_size = mono_class_data_size (class);
1916 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1917 if (class->interface_offsets_count) {
1918 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1919 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1920 mono_stats.imt_number_of_tables++;
1921 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1924 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1925 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1928 mono_stats.used_class_count++;
1929 mono_stats.class_vtable_size += vtable_size;
1930 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1933 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1935 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1937 vt->rank = class->rank;
1938 vt->domain = domain;
1940 mono_class_compute_gc_descriptor (class);
1942 * We can't use typed allocation in the non-root domains, since the
1943 * collector needs the GC descriptor stored in the vtable even after
1944 * the mempool containing the vtable is destroyed when the domain is
1945 * unloaded. An alternative might be to allocate vtables in the GC
1946 * heap, but this does not seem to work (it leads to crashes inside
1947 * libgc). If that approach is tried, two gc descriptors need to be
1948 * allocated for each class: one for the root domain, and one for all
1949 * other domains. The second descriptor should contain a bit for the
1950 * vtable field in MonoObject, since we can no longer assume the
1951 * vtable is reachable by other roots after the appdomain is unloaded.
1953 #ifdef HAVE_BOEHM_GC
1954 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1955 vt->gc_descr = GC_NO_DESCRIPTOR;
1958 vt->gc_descr = class->gc_descr;
1960 gc_bits = mono_gc_get_vtable_bits (class);
1961 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1963 vt->gc_bits = gc_bits;
1966 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1967 if (class->has_static_refs) {
1968 gpointer statics_gc_descr;
1970 gsize default_bitmap [4] = {0};
1973 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1974 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1975 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1976 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1977 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1978 if (bitmap != default_bitmap)
1981 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1983 vt->has_static_fields = TRUE;
1984 mono_stats.class_static_data_size += class_size;
1989 while ((field = mono_class_get_fields (class, &iter))) {
1990 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1992 if (mono_field_is_deleted (field))
1994 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1995 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1996 if (special_static != SPECIAL_STATIC_NONE) {
1997 guint32 size, offset;
1999 gsize default_bitmap [4] = {0};
2004 if (mono_type_is_reference (field->type)) {
2005 default_bitmap [0] = 1;
2007 bitmap = default_bitmap;
2008 } else if (mono_type_is_struct (field->type)) {
2009 fclass = mono_class_from_mono_type (field->type);
2010 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2011 numbits = max_set + 1;
2013 default_bitmap [0] = 0;
2015 bitmap = default_bitmap;
2017 size = mono_type_size (field->type, &align);
2018 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2019 if (!domain->special_static_fields)
2020 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2021 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2022 if (bitmap != default_bitmap)
2025 * This marks the field as special static to speed up the
2026 * checks in mono_field_static_get/set_value ().
2032 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2033 MonoClass *fklass = mono_class_from_mono_type (field->type);
2034 const char *data = mono_field_get_data (field);
2036 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2037 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2038 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2041 if (fklass->valuetype) {
2042 memcpy (t, data, mono_class_value_size (fklass, NULL));
2044 /* it's a pointer type: add check */
2045 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2052 vt->max_interface_id = class->max_interface_id;
2053 vt->interface_bitmap = class->interface_bitmap;
2055 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2056 // class->name, class->interface_offsets_count);
2058 if (! ARCH_USE_IMT) {
2059 /* initialize interface offsets */
2060 for (i = 0; i < class->interface_offsets_count; ++i) {
2061 int interface_id = class->interfaces_packed [i]->interface_id;
2062 int slot = class->interface_offsets_packed [i];
2063 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2067 /* Initialize vtable */
2068 if (callbacks.get_vtable_trampoline) {
2069 // This also covers the AOT case
2070 for (i = 0; i < class->vtable_size; ++i) {
2071 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2074 mono_class_setup_vtable (class);
2076 for (i = 0; i < class->vtable_size; ++i) {
2079 if ((cm = class->vtable [i]))
2080 vt->vtable [i] = arch_create_jit_trampoline (cm);
2084 if (ARCH_USE_IMT && imt_table_bytes) {
2085 /* Now that the vtable is full, we can actually fill up the IMT */
2086 if (callbacks.get_imt_trampoline) {
2087 /* lazy construction of the IMT entries enabled */
2088 for (i = 0; i < MONO_IMT_SIZE; ++i)
2089 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2091 build_imt (class, vt, domain, interface_offsets, NULL);
2096 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2097 * re-acquire them and check if another thread has created the vtable in the meantime.
2099 /* Special case System.MonoType to avoid infinite recursion */
2100 if (class != mono_defaults.monotype_class) {
2101 /*FIXME check for OOM*/
2102 vt->type = mono_type_get_object (domain, &class->byval_arg);
2103 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2104 /* This is unregistered in
2105 unregister_vtable_reflection_type() in
2107 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2110 if (class->contextbound)
2115 /* class_vtable_array keeps an array of created vtables
2117 g_ptr_array_add (domain->class_vtable_array, vt);
2118 /* class->runtime_info is protected by the loader lock, both when
2119 * it it enlarged and when it is stored info.
2123 * Store the vtable in class->runtime_info.
2124 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2126 mono_memory_barrier ();
2128 old_info = class->runtime_info;
2129 if (old_info && old_info->max_domain >= domain->domain_id) {
2130 /* someone already created a large enough runtime info */
2131 old_info->domain_vtables [domain->domain_id] = vt;
2133 int new_size = domain->domain_id;
2135 new_size = MAX (new_size, old_info->max_domain);
2137 /* make the new size a power of two */
2139 while (new_size > i)
2142 /* this is a bounded memory retention issue: may want to
2143 * handle it differently when we'll have a rcu-like system.
2145 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2146 runtime_info->max_domain = new_size - 1;
2147 /* copy the stuff from the older info */
2149 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2151 runtime_info->domain_vtables [domain->domain_id] = vt;
2153 mono_memory_barrier ();
2154 class->runtime_info = runtime_info;
2157 if (class == mono_defaults.monotype_class) {
2158 /*FIXME check for OOM*/
2159 vt->type = mono_type_get_object (domain, &class->byval_arg);
2160 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2161 /* This is unregistered in
2162 unregister_vtable_reflection_type() in
2164 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2167 mono_domain_unlock (domain);
2168 mono_loader_unlock ();
2170 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2171 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2172 mono_raise_exception (mono_class_get_exception_for_failure (class));
2174 /* make sure the parent is initialized */
2175 /*FIXME shouldn't this fail the current type?*/
2177 mono_class_vtable_full (domain, class->parent, raise_on_error);
2183 * mono_class_proxy_vtable:
2184 * @domain: the application domain
2185 * @remove_class: the remote class
2187 * Creates a vtable for transparent proxies. It is basically
2188 * a copy of the real vtable of the class wrapped in @remote_class,
2189 * but all function pointers invoke the remoting functions, and
2190 * vtable->klass points to the transparent proxy class, and not to @class.
2193 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2196 MonoVTable *vt, *pvt;
2197 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2199 GSList *extra_interfaces = NULL;
2200 MonoClass *class = remote_class->proxy_class;
2201 gpointer *interface_offsets;
2205 #ifdef COMPRESSED_INTERFACE_BITMAP
2209 vt = mono_class_vtable (domain, class);
2210 g_assert (vt); /*FIXME property handle failure*/
2211 max_interface_id = vt->max_interface_id;
2213 /* Calculate vtable space for extra interfaces */
2214 for (j = 0; j < remote_class->interface_count; j++) {
2215 MonoClass* iclass = remote_class->interfaces[j];
2219 /*FIXME test for interfaces with variant generic arguments*/
2220 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2221 continue; /* interface implemented by the class */
2222 if (g_slist_find (extra_interfaces, iclass))
2225 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2227 method_count = mono_class_num_methods (iclass);
2229 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2230 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2232 for (i = 0; i < ifaces->len; ++i) {
2233 MonoClass *ic = g_ptr_array_index (ifaces, i);
2234 /*FIXME test for interfaces with variant generic arguments*/
2235 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2236 continue; /* interface implemented by the class */
2237 if (g_slist_find (extra_interfaces, ic))
2239 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2240 method_count += mono_class_num_methods (ic);
2242 g_ptr_array_free (ifaces, TRUE);
2245 extra_interface_vtsize += method_count * sizeof (gpointer);
2246 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2250 mono_stats.imt_number_of_tables++;
2251 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2252 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2253 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2255 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2256 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2259 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2261 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2263 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2265 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2266 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2268 pvt->klass = mono_defaults.transparent_proxy_class;
2269 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2270 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2272 /* initialize vtable */
2273 mono_class_setup_vtable (class);
2274 for (i = 0; i < class->vtable_size; ++i) {
2277 if ((cm = class->vtable [i]))
2278 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2280 pvt->vtable [i] = NULL;
2283 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2284 /* create trampolines for abstract methods */
2285 for (k = class; k; k = k->parent) {
2287 gpointer iter = NULL;
2288 while ((m = mono_class_get_methods (k, &iter)))
2289 if (!pvt->vtable [m->slot])
2290 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2294 pvt->max_interface_id = max_interface_id;
2295 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2296 #ifdef COMPRESSED_INTERFACE_BITMAP
2297 bitmap = g_malloc0 (bsize);
2299 bitmap = mono_domain_alloc0 (domain, bsize);
2302 if (! ARCH_USE_IMT) {
2303 /* initialize interface offsets */
2304 for (i = 0; i < class->interface_offsets_count; ++i) {
2305 int interface_id = class->interfaces_packed [i]->interface_id;
2306 int slot = class->interface_offsets_packed [i];
2307 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2310 for (i = 0; i < class->interface_offsets_count; ++i) {
2311 int interface_id = class->interfaces_packed [i]->interface_id;
2312 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2315 if (extra_interfaces) {
2316 int slot = class->vtable_size;
2322 /* Create trampolines for the methods of the interfaces */
2323 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2324 interf = list_item->data;
2326 if (! ARCH_USE_IMT) {
2327 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2329 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2333 while ((cm = mono_class_get_methods (interf, &iter)))
2334 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2336 slot += mono_class_num_methods (interf);
2338 if (! ARCH_USE_IMT) {
2339 g_slist_free (extra_interfaces);
2344 /* Now that the vtable is full, we can actually fill up the IMT */
2345 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2346 if (extra_interfaces) {
2347 g_slist_free (extra_interfaces);
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2353 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2354 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2357 pvt->interface_bitmap = bitmap;
2363 * mono_class_field_is_special_static:
2365 * Returns whether @field is a thread/context static field.
2368 mono_class_field_is_special_static (MonoClassField *field)
2370 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2372 if (mono_field_is_deleted (field))
2374 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2375 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2382 * mono_class_field_get_special_static_type:
2383 * @field: The MonoClassField describing the field.
2385 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2386 * SPECIAL_STATIC_NONE otherwise.
2389 mono_class_field_get_special_static_type (MonoClassField *field)
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2392 return SPECIAL_STATIC_NONE;
2393 if (mono_field_is_deleted (field))
2394 return SPECIAL_STATIC_NONE;
2395 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2396 return field_is_special_static (field->parent, field);
2397 return SPECIAL_STATIC_NONE;
2401 * mono_class_has_special_static_fields:
2403 * Returns whenever @klass has any thread/context static fields.
2406 mono_class_has_special_static_fields (MonoClass *klass)
2408 MonoClassField *field;
2412 while ((field = mono_class_get_fields (klass, &iter))) {
2413 g_assert (field->parent == klass);
2414 if (mono_class_field_is_special_static (field))
2422 * create_remote_class_key:
2423 * Creates an array of pointers that can be used as a hash key for a remote class.
2424 * The first element of the array is the number of pointers.
2427 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2432 if (remote_class == NULL) {
2433 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2434 key = g_malloc (sizeof(gpointer) * 3);
2435 key [0] = GINT_TO_POINTER (2);
2436 key [1] = mono_defaults.marshalbyrefobject_class;
2437 key [2] = extra_class;
2439 key = g_malloc (sizeof(gpointer) * 2);
2440 key [0] = GINT_TO_POINTER (1);
2441 key [1] = extra_class;
2444 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2445 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2446 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2447 key [1] = remote_class->proxy_class;
2449 // Keep the list of interfaces sorted
2450 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2451 if (extra_class && remote_class->interfaces [i] > extra_class) {
2452 key [j++] = extra_class;
2455 key [j] = remote_class->interfaces [i];
2458 key [j] = extra_class;
2460 // Replace the old class. The interface list is the same
2461 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2463 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2464 for (i = 0; i < remote_class->interface_count; i++)
2465 key [2 + i] = remote_class->interfaces [i];
2473 * copy_remote_class_key:
2475 * Make a copy of KEY in the domain and return the copy.
2478 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2480 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2481 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2483 memcpy (mp_key, key, key_size);
2489 * mono_remote_class:
2490 * @domain: the application domain
2491 * @class_name: name of the remote class
2493 * Creates and initializes a MonoRemoteClass object for a remote type.
2495 * Can raise an exception on failure.
2498 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2501 MonoRemoteClass *rc;
2502 gpointer* key, *mp_key;
2505 key = create_remote_class_key (NULL, proxy_class);
2507 mono_domain_lock (domain);
2508 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2512 mono_domain_unlock (domain);
2516 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2517 if (!mono_error_ok (&error)) {
2519 mono_domain_unlock (domain);
2520 mono_error_raise_exception (&error);
2523 mp_key = copy_remote_class_key (domain, key);
2527 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2528 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2529 rc->interface_count = 1;
2530 rc->interfaces [0] = proxy_class;
2531 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2533 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2534 rc->interface_count = 0;
2535 rc->proxy_class = proxy_class;
2538 rc->default_vtable = NULL;
2539 rc->xdomain_vtable = NULL;
2540 rc->proxy_class_name = name;
2541 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2543 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2545 mono_domain_unlock (domain);
2550 * clone_remote_class:
2551 * Creates a copy of the remote_class, adding the provided class or interface
2553 static MonoRemoteClass*
2554 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2556 MonoRemoteClass *rc;
2557 gpointer* key, *mp_key;
2559 key = create_remote_class_key (remote_class, extra_class);
2560 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2566 mp_key = copy_remote_class_key (domain, key);
2570 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2572 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2573 rc->proxy_class = remote_class->proxy_class;
2574 rc->interface_count = remote_class->interface_count + 1;
2576 // Keep the list of interfaces sorted, since the hash key of
2577 // the remote class depends on this
2578 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2579 if (remote_class->interfaces [i] > extra_class && i == j)
2580 rc->interfaces [j++] = extra_class;
2581 rc->interfaces [j] = remote_class->interfaces [i];
2584 rc->interfaces [j] = extra_class;
2586 // Replace the old class. The interface array is the same
2587 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2588 rc->proxy_class = extra_class;
2589 rc->interface_count = remote_class->interface_count;
2590 if (rc->interface_count > 0)
2591 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2594 rc->default_vtable = NULL;
2595 rc->xdomain_vtable = NULL;
2596 rc->proxy_class_name = remote_class->proxy_class_name;
2598 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2604 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2606 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2607 mono_domain_lock (domain);
2608 if (rp->target_domain_id != -1) {
2609 if (remote_class->xdomain_vtable == NULL)
2610 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2611 mono_domain_unlock (domain);
2612 mono_loader_unlock ();
2613 return remote_class->xdomain_vtable;
2615 if (remote_class->default_vtable == NULL) {
2618 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2619 klass = mono_class_from_mono_type (type);
2620 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2621 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2623 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2626 mono_domain_unlock (domain);
2627 mono_loader_unlock ();
2628 return remote_class->default_vtable;
2632 * mono_upgrade_remote_class:
2633 * @domain: the application domain
2634 * @tproxy: the proxy whose remote class has to be upgraded.
2635 * @klass: class to which the remote class can be casted.
2637 * Updates the vtable of the remote class by adding the necessary method slots
2638 * and interface offsets so it can be safely casted to klass. klass can be a
2639 * class or an interface.
2642 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2644 MonoTransparentProxy *tproxy;
2645 MonoRemoteClass *remote_class;
2646 gboolean redo_vtable;
2648 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2649 mono_domain_lock (domain);
2651 tproxy = (MonoTransparentProxy*) proxy_object;
2652 remote_class = tproxy->remote_class;
2654 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2657 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2658 if (remote_class->interfaces [i] == klass)
2659 redo_vtable = FALSE;
2662 redo_vtable = (remote_class->proxy_class != klass);
2666 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2667 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2676 * mono_object_get_virtual_method:
2677 * @obj: object to operate on.
2680 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2681 * the instance of a callvirt of method.
2684 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2687 MonoMethod **vtable;
2689 MonoMethod *res = NULL;
2691 klass = mono_object_class (obj);
2692 if (klass == mono_defaults.transparent_proxy_class) {
2693 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2699 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2702 mono_class_setup_vtable (klass);
2703 vtable = klass->vtable;
2705 if (method->slot == -1) {
2706 /* method->slot might not be set for instances of generic methods */
2707 if (method->is_inflated) {
2708 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2709 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2712 g_assert_not_reached ();
2716 /* check method->slot is a valid index: perform isinstance? */
2717 if (method->slot != -1) {
2718 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2720 gboolean variance_used = FALSE;
2721 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2722 g_assert (iface_offset > 0);
2723 res = vtable [iface_offset + method->slot];
2726 res = vtable [method->slot];
2731 /* It may be an interface, abstract class method or generic method */
2732 if (!res || mono_method_signature (res)->generic_param_count)
2735 /* generic methods demand invoke_with_check */
2736 if (mono_method_signature (res)->generic_param_count)
2737 res = mono_marshal_get_remoting_invoke_with_check (res);
2740 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2741 res = mono_cominterop_get_invoke (res);
2744 res = mono_marshal_get_remoting_invoke (res);
2747 if (method->is_inflated) {
2748 /* Have to inflate the result */
2749 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2759 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2761 g_error ("runtime invoke called on uninitialized runtime");
2765 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2768 * mono_runtime_invoke:
2769 * @method: method to invoke
2770 * @obJ: object instance
2771 * @params: arguments to the method
2772 * @exc: exception information.
2774 * Invokes the method represented by @method on the object @obj.
2776 * obj is the 'this' pointer, it should be NULL for static
2777 * methods, a MonoObject* for object instances and a pointer to
2778 * the value type for value types.
2780 * The params array contains the arguments to the method with the
2781 * same convention: MonoObject* pointers for object instances and
2782 * pointers to the value type otherwise.
2784 * From unmanaged code you'll usually use the
2785 * mono_runtime_invoke() variant.
2787 * Note that this function doesn't handle virtual methods for
2788 * you, it will exec the exact method you pass: we still need to
2789 * expose a function to lookup the derived class implementation
2790 * of a virtual method (there are examples of this in the code,
2793 * You can pass NULL as the exc argument if you don't want to
2794 * catch exceptions, otherwise, *exc will be set to the exception
2795 * thrown, if any. if an exception is thrown, you can't use the
2796 * MonoObject* result from the function.
2798 * If the method returns a value type, it is boxed in an object
2802 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2806 if (mono_runtime_get_no_exec ())
2807 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2809 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2810 mono_profiler_method_start_invoke (method);
2812 result = default_mono_runtime_invoke (method, obj, params, exc);
2814 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2815 mono_profiler_method_end_invoke (method);
2821 * mono_method_get_unmanaged_thunk:
2822 * @method: method to generate a thunk for.
2824 * Returns an unmanaged->managed thunk that can be used to call
2825 * a managed method directly from C.
2827 * The thunk's C signature closely matches the managed signature:
2829 * C#: public bool Equals (object obj);
2830 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2831 * MonoObject*, MonoException**);
2833 * The 1st ("this") parameter must not be used with static methods:
2835 * C#: public static bool ReferenceEquals (object a, object b);
2836 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2839 * The last argument must be a non-null pointer of a MonoException* pointer.
2840 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2841 * exception has been thrown in managed code. Otherwise it will point
2842 * to the MonoException* caught by the thunk. In this case, the result of
2843 * the thunk is undefined:
2845 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2846 * MonoException *ex = NULL;
2847 * Equals func = mono_method_get_unmanaged_thunk (method);
2848 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2850 * // handle exception
2853 * The calling convention of the thunk matches the platform's default
2854 * convention. This means that under Windows, C declarations must
2855 * contain the __stdcall attribute:
2857 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2858 * MonoObject*, MonoException**);
2862 * Value type arguments and return values are treated as they were objects:
2864 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2865 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2867 * Arguments must be properly boxed upon trunk's invocation, while return
2868 * values must be unboxed.
2871 mono_method_get_unmanaged_thunk (MonoMethod *method)
2873 method = mono_marshal_get_thunk_invoke_wrapper (method);
2874 return mono_compile_method (method);
2878 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2882 /* object fields cannot be byref, so we don't need a
2884 gpointer *p = (gpointer*)dest;
2891 case MONO_TYPE_BOOLEAN:
2893 case MONO_TYPE_U1: {
2894 guint8 *p = (guint8*)dest;
2895 *p = value ? *(guint8*)value : 0;
2900 case MONO_TYPE_CHAR: {
2901 guint16 *p = (guint16*)dest;
2902 *p = value ? *(guint16*)value : 0;
2905 #if SIZEOF_VOID_P == 4
2910 case MONO_TYPE_U4: {
2911 gint32 *p = (gint32*)dest;
2912 *p = value ? *(gint32*)value : 0;
2915 #if SIZEOF_VOID_P == 8
2920 case MONO_TYPE_U8: {
2921 gint64 *p = (gint64*)dest;
2922 *p = value ? *(gint64*)value : 0;
2925 case MONO_TYPE_R4: {
2926 float *p = (float*)dest;
2927 *p = value ? *(float*)value : 0;
2930 case MONO_TYPE_R8: {
2931 double *p = (double*)dest;
2932 *p = value ? *(double*)value : 0;
2935 case MONO_TYPE_STRING:
2936 case MONO_TYPE_SZARRAY:
2937 case MONO_TYPE_CLASS:
2938 case MONO_TYPE_OBJECT:
2939 case MONO_TYPE_ARRAY:
2940 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2942 case MONO_TYPE_FNPTR:
2943 case MONO_TYPE_PTR: {
2944 gpointer *p = (gpointer*)dest;
2945 *p = deref_pointer? *(gpointer*)value: value;
2948 case MONO_TYPE_VALUETYPE:
2949 /* note that 't' and 'type->type' can be different */
2950 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2951 t = mono_class_enum_basetype (type->data.klass)->type;
2954 MonoClass *class = mono_class_from_mono_type (type);
2955 int size = mono_class_value_size (class, NULL);
2957 mono_gc_bzero (dest, size);
2959 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2962 case MONO_TYPE_GENERICINST:
2963 t = type->data.generic_class->container_class->byval_arg.type;
2966 g_error ("got type %x", type->type);
2971 * mono_field_set_value:
2972 * @obj: Instance object
2973 * @field: MonoClassField describing the field to set
2974 * @value: The value to be set
2976 * Sets the value of the field described by @field in the object instance @obj
2977 * to the value passed in @value. This method should only be used for instance
2978 * fields. For static fields, use mono_field_static_set_value.
2980 * The value must be on the native format of the field type.
2983 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2987 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2989 dest = (char*)obj + field->offset;
2990 set_value (field->type, dest, value, FALSE);
2994 * mono_field_static_set_value:
2995 * @field: MonoClassField describing the field to set
2996 * @value: The value to be set
2998 * Sets the value of the static field described by @field
2999 * to the value passed in @value.
3001 * The value must be on the native format of the field type.
3004 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3008 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3009 /* you cant set a constant! */
3010 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3012 if (field->offset == -1) {
3013 /* Special static */
3016 mono_domain_lock (vt->domain);
3017 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3018 mono_domain_unlock (vt->domain);
3019 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3021 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3023 set_value (field->type, dest, value, FALSE);
3027 * mono_vtable_get_static_field_data:
3029 * Internal use function: return a pointer to the memory holding the static fields
3030 * for a class or NULL if there are no static fields.
3031 * This is exported only for use by the debugger.
3034 mono_vtable_get_static_field_data (MonoVTable *vt)
3036 if (!vt->has_static_fields)
3038 return vt->vtable [vt->klass->vtable_size];
3042 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3046 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3047 if (field->offset == -1) {
3048 /* Special static */
3051 mono_domain_lock (vt->domain);
3052 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3053 mono_domain_unlock (vt->domain);
3054 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3056 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3059 src = (guint8*)obj + field->offset;
3066 * mono_field_get_value:
3067 * @obj: Object instance
3068 * @field: MonoClassField describing the field to fetch information from
3069 * @value: pointer to the location where the value will be stored
3071 * Use this routine to get the value of the field @field in the object
3074 * The pointer provided by value must be of the field type, for reference
3075 * types this is a MonoObject*, for value types its the actual pointer to
3080 * mono_field_get_value (obj, int_field, &i);
3083 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3089 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3091 src = (char*)obj + field->offset;
3092 set_value (field->type, value, src, TRUE);
3096 * mono_field_get_value_object:
3097 * @domain: domain where the object will be created (if boxing)
3098 * @field: MonoClassField describing the field to fetch information from
3099 * @obj: The object instance for the field.
3101 * Returns: a new MonoObject with the value from the given field. If the
3102 * field represents a value type, the value is boxed.
3106 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3110 MonoVTable *vtable = NULL;
3112 gboolean is_static = FALSE;
3113 gboolean is_ref = FALSE;
3114 gboolean is_literal = FALSE;
3115 gboolean is_ptr = FALSE;
3117 MonoType *type = mono_field_get_type_checked (field, &error);
3119 if (!mono_error_ok (&error))
3120 mono_error_raise_exception (&error);
3122 switch (type->type) {
3123 case MONO_TYPE_STRING:
3124 case MONO_TYPE_OBJECT:
3125 case MONO_TYPE_CLASS:
3126 case MONO_TYPE_ARRAY:
3127 case MONO_TYPE_SZARRAY:
3132 case MONO_TYPE_BOOLEAN:
3135 case MONO_TYPE_CHAR:
3144 case MONO_TYPE_VALUETYPE:
3145 is_ref = type->byref;
3147 case MONO_TYPE_GENERICINST:
3148 is_ref = !mono_type_generic_inst_is_valuetype (type);
3154 g_error ("type 0x%x not handled in "
3155 "mono_field_get_value_object", type->type);
3159 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3162 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3166 vtable = mono_class_vtable (domain, field->parent);
3168 char *name = mono_type_get_full_name (field->parent);
3169 /*FIXME extend this to use the MonoError api*/
3170 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3174 if (!vtable->initialized)
3175 mono_runtime_class_init (vtable);
3183 get_default_field_value (domain, field, &o);
3184 } else if (is_static) {
3185 mono_field_static_get_value (vtable, field, &o);
3187 mono_field_get_value (obj, field, &o);
3193 static MonoMethod *m;
3199 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3200 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3206 get_default_field_value (domain, field, v);
3207 } else if (is_static) {
3208 mono_field_static_get_value (vtable, field, v);
3210 mono_field_get_value (obj, field, v);
3213 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3215 args [1] = mono_type_get_object (mono_domain_get (), type);
3217 return mono_runtime_invoke (m, NULL, args, NULL);
3220 /* boxed value type */
3221 klass = mono_class_from_mono_type (type);
3223 if (mono_class_is_nullable (klass))
3224 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3226 o = mono_object_new (domain, klass);
3227 v = ((gchar *) o) + sizeof (MonoObject);
3230 get_default_field_value (domain, field, v);
3231 } else if (is_static) {
3232 mono_field_static_get_value (vtable, field, v);
3234 mono_field_get_value (obj, field, v);
3241 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3244 const char *p = blob;
3245 mono_metadata_decode_blob_size (p, &p);
3248 case MONO_TYPE_BOOLEAN:
3251 *(guint8 *) value = *p;
3253 case MONO_TYPE_CHAR:
3256 *(guint16*) value = read16 (p);
3260 *(guint32*) value = read32 (p);
3264 *(guint64*) value = read64 (p);
3267 readr4 (p, (float*) value);
3270 readr8 (p, (double*) value);
3272 case MONO_TYPE_STRING:
3273 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3275 case MONO_TYPE_CLASS:
3276 *(gpointer*) value = NULL;
3280 g_warning ("type 0x%02x should not be in constant table", type);
3286 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3288 MonoTypeEnum def_type;
3291 data = mono_class_get_field_default_value (field, &def_type);
3292 mono_get_constant_value_from_blob (domain, def_type, data, value);
3296 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3300 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3302 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3303 get_default_field_value (vt->domain, field, value);
3307 if (field->offset == -1) {
3308 /* Special static */
3309 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3310 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3312 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3314 set_value (field->type, value, src, TRUE);
3318 * mono_field_static_get_value:
3319 * @vt: vtable to the object
3320 * @field: MonoClassField describing the field to fetch information from
3321 * @value: where the value is returned
3323 * Use this routine to get the value of the static field @field value.
3325 * The pointer provided by value must be of the field type, for reference
3326 * types this is a MonoObject*, for value types its the actual pointer to
3331 * mono_field_static_get_value (vt, int_field, &i);
3334 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3336 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3340 * mono_property_set_value:
3341 * @prop: MonoProperty to set
3342 * @obj: instance object on which to act
3343 * @params: parameters to pass to the propery
3344 * @exc: optional exception
3346 * Invokes the property's set method with the given arguments on the
3347 * object instance obj (or NULL for static properties).
3349 * You can pass NULL as the exc argument if you don't want to
3350 * catch exceptions, otherwise, *exc will be set to the exception
3351 * thrown, if any. if an exception is thrown, you can't use the
3352 * MonoObject* result from the function.
3355 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3357 default_mono_runtime_invoke (prop->set, obj, params, exc);
3361 * mono_property_get_value:
3362 * @prop: MonoProperty to fetch
3363 * @obj: instance object on which to act
3364 * @params: parameters to pass to the propery
3365 * @exc: optional exception
3367 * Invokes the property's get method with the given arguments on the
3368 * object instance obj (or NULL for static properties).
3370 * You can pass NULL as the exc argument if you don't want to
3371 * catch exceptions, otherwise, *exc will be set to the exception
3372 * thrown, if any. if an exception is thrown, you can't use the
3373 * MonoObject* result from the function.
3375 * Returns: the value from invoking the get method on the property.
3378 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3380 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3384 * mono_nullable_init:
3385 * @buf: The nullable structure to initialize.
3386 * @value: the value to initialize from
3387 * @klass: the type for the object
3389 * Initialize the nullable structure pointed to by @buf from @value which
3390 * should be a boxed value type. The size of @buf should be able to hold
3391 * as much data as the @klass->instance_size (which is the number of bytes
3392 * that will be copies).
3394 * Since Nullables have variable structure, we can not define a C
3395 * structure for them.
3398 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3400 MonoClass *param_class = klass->cast_class;
3402 mono_class_setup_fields_locking (klass);
3403 g_assert (klass->fields_inited);
3405 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3406 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3408 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3410 if (param_class->has_references)
3411 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3413 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3415 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3420 * mono_nullable_box:
3421 * @buf: The buffer representing the data to be boxed
3422 * @klass: the type to box it as.
3424 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3428 mono_nullable_box (guint8 *buf, MonoClass *klass)
3430 MonoClass *param_class = klass->cast_class;
3432 mono_class_setup_fields_locking (klass);
3433 g_assert (klass->fields_inited);
3435 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3436 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3438 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3439 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3440 if (param_class->has_references)
3441 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3443 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3451 * mono_get_delegate_invoke:
3452 * @klass: The delegate class
3454 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3457 mono_get_delegate_invoke (MonoClass *klass)
3461 /* This is called at runtime, so avoid the slower search in metadata */
3462 mono_class_setup_methods (klass);
3463 if (klass->exception_type)
3465 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3470 * mono_runtime_delegate_invoke:
3471 * @delegate: pointer to a delegate object.
3472 * @params: parameters for the delegate.
3473 * @exc: Pointer to the exception result.
3475 * Invokes the delegate method @delegate with the parameters provided.
3477 * You can pass NULL as the exc argument if you don't want to
3478 * catch exceptions, otherwise, *exc will be set to the exception
3479 * thrown, if any. if an exception is thrown, you can't use the
3480 * MonoObject* result from the function.
3483 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3486 MonoClass *klass = delegate->vtable->klass;
3488 im = mono_get_delegate_invoke (klass);
3490 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3492 return mono_runtime_invoke (im, delegate, params, exc);
3495 static char **main_args = NULL;
3496 static int num_main_args;
3499 * mono_runtime_get_main_args:
3501 * Returns: a MonoArray with the arguments passed to the main program
3504 mono_runtime_get_main_args (void)
3508 MonoDomain *domain = mono_domain_get ();
3513 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3515 for (i = 0; i < num_main_args; ++i)
3516 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3522 free_main_args (void)
3526 for (i = 0; i < num_main_args; ++i)
3527 g_free (main_args [i]);
3532 * mono_runtime_run_main:
3533 * @method: the method to start the application with (usually Main)
3534 * @argc: number of arguments from the command line
3535 * @argv: array of strings from the command line
3536 * @exc: excetption results
3538 * Execute a standard Main() method (argc/argv contains the
3539 * executable name). This method also sets the command line argument value
3540 * needed by System.Environment.
3545 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3549 MonoArray *args = NULL;
3550 MonoDomain *domain = mono_domain_get ();
3551 gchar *utf8_fullpath;
3552 MonoMethodSignature *sig;
3554 g_assert (method != NULL);
3556 mono_thread_set_main (mono_thread_current ());
3558 main_args = g_new0 (char*, argc);
3559 num_main_args = argc;
3561 if (!g_path_is_absolute (argv [0])) {
3562 gchar *basename = g_path_get_basename (argv [0]);
3563 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3567 utf8_fullpath = mono_utf8_from_external (fullpath);
3568 if(utf8_fullpath == NULL) {
3569 /* Printing the arg text will cause glib to
3570 * whinge about "Invalid UTF-8", but at least
3571 * its relevant, and shows the problem text
3574 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3575 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3582 utf8_fullpath = mono_utf8_from_external (argv[0]);
3583 if(utf8_fullpath == NULL) {
3584 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3585 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3590 main_args [0] = utf8_fullpath;
3592 for (i = 1; i < argc; ++i) {
3595 utf8_arg=mono_utf8_from_external (argv[i]);
3596 if(utf8_arg==NULL) {
3597 /* Ditto the comment about Invalid UTF-8 here */
3598 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3599 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3603 main_args [i] = utf8_arg;
3608 sig = mono_method_signature (method);
3610 g_print ("Unable to load Main method.\n");
3614 if (sig->param_count) {
3615 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3616 for (i = 0; i < argc; ++i) {
3617 /* The encodings should all work, given that
3618 * we've checked all these args for the
3621 gchar *str = mono_utf8_from_external (argv [i]);
3622 MonoString *arg = mono_string_new (domain, str);
3623 mono_array_setref (args, i, arg);
3627 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3630 mono_assembly_set_main (method->klass->image->assembly);
3632 return mono_runtime_exec_main (method, args, exc);
3636 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3638 static MonoMethod *serialize_method;
3643 if (!serialize_method) {
3644 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3645 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3648 if (!serialize_method) {
3653 g_assert (!mono_object_class (obj)->marshalbyref);
3657 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3665 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3667 static MonoMethod *deserialize_method;
3672 if (!deserialize_method) {
3673 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3674 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3676 if (!deserialize_method) {
3683 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3691 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3693 static MonoMethod *get_proxy_method;
3695 MonoDomain *domain = mono_domain_get ();
3696 MonoRealProxy *real_proxy;
3697 MonoReflectionType *reflection_type;
3698 MonoTransparentProxy *transparent_proxy;
3700 if (!get_proxy_method)
3701 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3703 g_assert (obj->vtable->klass->marshalbyref);
3705 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3706 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3708 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3709 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3712 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3716 return (MonoObject*) transparent_proxy;
3720 * mono_object_xdomain_representation
3722 * @target_domain: a domain
3723 * @exc: pointer to a MonoObject*
3725 * Creates a representation of obj in the domain target_domain. This
3726 * is either a copy of obj arrived through via serialization and
3727 * deserialization or a proxy, depending on whether the object is
3728 * serializable or marshal by ref. obj must not be in target_domain.
3730 * If the object cannot be represented in target_domain, NULL is
3731 * returned and *exc is set to an appropriate exception.
3734 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3736 MonoObject *deserialized = NULL;
3737 gboolean failure = FALSE;
3741 if (mono_object_class (obj)->marshalbyref) {
3742 deserialized = make_transparent_proxy (obj, &failure, exc);
3744 MonoDomain *domain = mono_domain_get ();
3745 MonoObject *serialized;
3747 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3748 serialized = serialize_object (obj, &failure, exc);
3749 mono_domain_set_internal_with_options (target_domain, FALSE);
3751 deserialized = deserialize_object (serialized, &failure, exc);
3752 if (domain != target_domain)
3753 mono_domain_set_internal_with_options (domain, FALSE);
3756 return deserialized;
3759 /* Used in call_unhandled_exception_delegate */
3761 create_unhandled_exception_eventargs (MonoObject *exc)
3765 MonoMethod *method = NULL;
3766 MonoBoolean is_terminating = TRUE;
3769 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3772 mono_class_init (klass);
3774 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3775 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3779 args [1] = &is_terminating;
3781 obj = mono_object_new (mono_domain_get (), klass);
3782 mono_runtime_invoke (method, obj, args, NULL);
3787 /* Used in mono_unhandled_exception */
3789 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3790 MonoObject *e = NULL;
3792 MonoDomain *current_domain = mono_domain_get ();
3794 if (domain != current_domain)
3795 mono_domain_set_internal_with_options (domain, FALSE);
3797 g_assert (domain == mono_object_domain (domain->domain));
3799 if (mono_object_domain (exc) != domain) {
3800 MonoObject *serialization_exc;
3802 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3804 if (serialization_exc) {
3806 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3809 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3810 "System.Runtime.Serialization", "SerializationException",
3811 "Could not serialize unhandled exception.");
3815 g_assert (mono_object_domain (exc) == domain);
3817 pa [0] = domain->domain;
3818 pa [1] = create_unhandled_exception_eventargs (exc);
3819 mono_runtime_delegate_invoke (delegate, pa, &e);
3821 if (domain != current_domain)
3822 mono_domain_set_internal_with_options (current_domain, FALSE);
3826 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3827 if (!mono_error_ok (&error)) {
3828 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3829 mono_error_cleanup (&error);
3831 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3837 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3840 * mono_runtime_unhandled_exception_policy_set:
3841 * @policy: the new policy
3843 * This is a VM internal routine.
3845 * Sets the runtime policy for handling unhandled exceptions.
3848 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3849 runtime_unhandled_exception_policy = policy;
3853 * mono_runtime_unhandled_exception_policy_get:
3855 * This is a VM internal routine.
3857 * Gets the runtime policy for handling unhandled exceptions.
3859 MonoRuntimeUnhandledExceptionPolicy
3860 mono_runtime_unhandled_exception_policy_get (void) {
3861 return runtime_unhandled_exception_policy;
3865 * mono_unhandled_exception:
3866 * @exc: exception thrown
3868 * This is a VM internal routine.
3870 * We call this function when we detect an unhandled exception
3871 * in the default domain.
3873 * It invokes the * UnhandledException event in AppDomain or prints
3874 * a warning to the console
3877 mono_unhandled_exception (MonoObject *exc)
3879 MonoDomain *current_domain = mono_domain_get ();
3880 MonoDomain *root_domain = mono_get_root_domain ();
3881 MonoClassField *field;
3882 MonoObject *current_appdomain_delegate;
3883 MonoObject *root_appdomain_delegate;
3885 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3886 "UnhandledException");
3889 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3890 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3891 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3892 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3893 if (current_domain != root_domain) {
3894 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3896 current_appdomain_delegate = NULL;
3899 /* set exitcode only if we will abort the process */
3900 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3902 mono_environment_exitcode_set (1);
3903 mono_print_unhandled_exception (exc);
3905 if (root_appdomain_delegate) {
3906 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3908 if (current_appdomain_delegate) {
3909 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3916 * mono_runtime_exec_managed_code:
3917 * @domain: Application domain
3918 * @main_func: function to invoke from the execution thread
3919 * @main_args: parameter to the main_func
3921 * Launch a new thread to execute a function
3923 * main_func is called back from the thread with main_args as the
3924 * parameter. The callback function is expected to start Main()
3925 * eventually. This function then waits for all managed threads to
3927 * It is not necesseray anymore to execute managed code in a subthread,
3928 * so this function should not be used anymore by default: just
3929 * execute the code and then call mono_thread_manage ().
3932 mono_runtime_exec_managed_code (MonoDomain *domain,
3933 MonoMainThreadFunc main_func,
3936 mono_thread_create (domain, main_func, main_args);
3938 mono_thread_manage ();
3942 * Execute a standard Main() method (args doesn't contain the
3946 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3951 MonoCustomAttrInfo* cinfo;
3952 gboolean has_stathread_attribute;
3953 MonoInternalThread* thread = mono_thread_internal_current ();
3959 domain = mono_object_domain (args);
3960 if (!domain->entry_assembly) {
3962 MonoAssembly *assembly;
3964 assembly = method->klass->image->assembly;
3965 domain->entry_assembly = assembly;
3966 /* Domains created from another domain already have application_base and configuration_file set */
3967 if (domain->setup->application_base == NULL) {
3968 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3971 if (domain->setup->configuration_file == NULL) {
3972 str = g_strconcat (assembly->image->name, ".config", NULL);
3973 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3975 mono_set_private_bin_path_from_config (domain);
3979 cinfo = mono_custom_attrs_from_method (method);
3981 static MonoClass *stathread_attribute = NULL;
3982 if (!stathread_attribute)
3983 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3984 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3986 mono_custom_attrs_free (cinfo);
3988 has_stathread_attribute = FALSE;
3990 if (has_stathread_attribute) {
3991 thread->apartment_state = ThreadApartmentState_STA;
3993 thread->apartment_state = ThreadApartmentState_MTA;
3995 mono_thread_init_apartment_state ();
3997 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3999 /* FIXME: check signature of method */
4000 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4002 res = mono_runtime_invoke (method, NULL, pa, exc);
4004 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4008 mono_environment_exitcode_set (rval);
4010 mono_runtime_invoke (method, NULL, pa, exc);
4014 /* If the return type of Main is void, only
4015 * set the exitcode if an exception was thrown
4016 * (we don't want to blow away an
4017 * explicitly-set exit code)
4020 mono_environment_exitcode_set (rval);
4024 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4030 * mono_install_runtime_invoke:
4031 * @func: Function to install
4033 * This is a VM internal routine
4036 mono_install_runtime_invoke (MonoInvokeFunc func)
4038 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4043 * mono_runtime_invoke_array:
4044 * @method: method to invoke
4045 * @obJ: object instance
4046 * @params: arguments to the method
4047 * @exc: exception information.
4049 * Invokes the method represented by @method on the object @obj.
4051 * obj is the 'this' pointer, it should be NULL for static
4052 * methods, a MonoObject* for object instances and a pointer to
4053 * the value type for value types.
4055 * The params array contains the arguments to the method with the
4056 * same convention: MonoObject* pointers for object instances and
4057 * pointers to the value type otherwise. The _invoke_array
4058 * variant takes a C# object[] as the params argument (MonoArray
4059 * *params): in this case the value types are boxed inside the
4060 * respective reference representation.
4062 * From unmanaged code you'll usually use the
4063 * mono_runtime_invoke() variant.
4065 * Note that this function doesn't handle virtual methods for
4066 * you, it will exec the exact method you pass: we still need to
4067 * expose a function to lookup the derived class implementation
4068 * of a virtual method (there are examples of this in the code,
4071 * You can pass NULL as the exc argument if you don't want to
4072 * catch exceptions, otherwise, *exc will be set to the exception
4073 * thrown, if any. if an exception is thrown, you can't use the
4074 * MonoObject* result from the function.
4076 * If the method returns a value type, it is boxed in an object
4080 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4083 MonoMethodSignature *sig = mono_method_signature (method);
4084 gpointer *pa = NULL;
4087 gboolean has_byref_nullables = FALSE;
4089 if (NULL != params) {
4090 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4091 for (i = 0; i < mono_array_length (params); i++) {
4092 MonoType *t = sig->params [i];
4098 case MONO_TYPE_BOOLEAN:
4101 case MONO_TYPE_CHAR:
4110 case MONO_TYPE_VALUETYPE:
4111 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4112 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4113 pa [i] = mono_array_get (params, MonoObject*, i);
4115 has_byref_nullables = TRUE;
4117 /* MS seems to create the objects if a null is passed in */
4118 if (!mono_array_get (params, MonoObject*, i))
4119 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4123 * We can't pass the unboxed vtype byref to the callee, since
4124 * that would mean the callee would be able to modify boxed
4125 * primitive types. So we (and MS) make a copy of the boxed
4126 * object, pass that to the callee, and replace the original
4127 * boxed object in the arg array with the copy.
4129 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4130 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4131 mono_array_setref (params, i, copy);
4134 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4137 case MONO_TYPE_STRING:
4138 case MONO_TYPE_OBJECT:
4139 case MONO_TYPE_CLASS:
4140 case MONO_TYPE_ARRAY:
4141 case MONO_TYPE_SZARRAY:
4143 pa [i] = mono_array_addr (params, MonoObject*, i);
4144 // FIXME: I need to check this code path
4146 pa [i] = mono_array_get (params, MonoObject*, i);
4148 case MONO_TYPE_GENERICINST:
4150 t = &t->data.generic_class->container_class->this_arg;
4152 t = &t->data.generic_class->container_class->byval_arg;
4154 case MONO_TYPE_PTR: {
4157 /* The argument should be an IntPtr */
4158 arg = mono_array_get (params, MonoObject*, i);
4162 g_assert (arg->vtable->klass == mono_defaults.int_class);
4163 pa [i] = ((MonoIntPtr*)arg)->m_value;
4168 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4173 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4176 if (mono_class_is_nullable (method->klass)) {
4177 /* Need to create a boxed vtype instead */
4183 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4187 obj = mono_object_new (mono_domain_get (), method->klass);
4188 g_assert (obj); /*maybe we should raise a TLE instead?*/
4189 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4190 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4192 if (method->klass->valuetype)
4193 o = mono_object_unbox (obj);
4196 } else if (method->klass->valuetype) {
4197 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4200 mono_runtime_invoke (method, o, pa, exc);
4203 if (mono_class_is_nullable (method->klass)) {
4204 MonoObject *nullable;
4206 /* Convert the unboxed vtype into a Nullable structure */
4207 nullable = mono_object_new (mono_domain_get (), method->klass);
4209 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4210 obj = mono_object_unbox (nullable);
4213 /* obj must be already unboxed if needed */
4214 res = mono_runtime_invoke (method, obj, pa, exc);
4216 if (sig->ret->type == MONO_TYPE_PTR) {
4217 MonoClass *pointer_class;
4218 static MonoMethod *box_method;
4220 MonoObject *box_exc;
4223 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4224 * convert it to a Pointer object.
4226 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4228 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4230 g_assert (res->vtable->klass == mono_defaults.int_class);
4231 box_args [0] = ((MonoIntPtr*)res)->m_value;
4232 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4233 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4234 g_assert (!box_exc);
4237 if (has_byref_nullables) {
4239 * The runtime invoke wrapper already converted byref nullables back,
4240 * and stored them in pa, we just need to copy them back to the
4243 for (i = 0; i < mono_array_length (params); i++) {
4244 MonoType *t = sig->params [i];
4246 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4247 mono_array_setref (params, i, pa [i]);
4256 arith_overflow (void)
4258 mono_raise_exception (mono_get_exception_overflow ());
4262 * mono_object_allocate:
4263 * @size: number of bytes to allocate
4265 * This is a very simplistic routine until we have our GC-aware
4268 * Returns: an allocated object of size @size, or NULL on failure.
4270 static inline void *
4271 mono_object_allocate (size_t size, MonoVTable *vtable)
4274 mono_stats.new_object_count++;
4275 ALLOC_OBJECT (o, vtable, size);
4281 * mono_object_allocate_ptrfree:
4282 * @size: number of bytes to allocate
4284 * Note that the memory allocated is not zeroed.
4285 * Returns: an allocated object of size @size, or NULL on failure.
4287 static inline void *
4288 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4291 mono_stats.new_object_count++;
4292 ALLOC_PTRFREE (o, vtable, size);
4296 static inline void *
4297 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4300 ALLOC_TYPED (o, size, vtable);
4301 mono_stats.new_object_count++;
4308 * @klass: the class of the object that we want to create
4310 * Returns: a newly created object whose definition is
4311 * looked up using @klass. This will not invoke any constructors,
4312 * so the consumer of this routine has to invoke any constructors on
4313 * its own to initialize the object.
4315 * It returns NULL on failure.
4318 mono_object_new (MonoDomain *domain, MonoClass *klass)
4322 MONO_ARCH_SAVE_REGS;
4323 vtable = mono_class_vtable (domain, klass);
4326 return mono_object_new_specific (vtable);
4330 * mono_object_new_pinned:
4332 * Same as mono_object_new, but the returned object will be pinned.
4333 * For SGEN, these objects will only be freed at appdomain unload.
4336 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4340 MONO_ARCH_SAVE_REGS;
4341 vtable = mono_class_vtable (domain, klass);
4346 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4348 return mono_object_new_specific (vtable);
4353 * mono_object_new_specific:
4354 * @vtable: the vtable of the object that we want to create
4356 * Returns: A newly created object with class and domain specified
4360 mono_object_new_specific (MonoVTable *vtable)
4364 MONO_ARCH_SAVE_REGS;
4366 /* check for is_com_object for COM Interop */
4367 if (vtable->remote || vtable->klass->is_com_object)
4370 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4373 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4376 mono_class_init (klass);
4378 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4380 vtable->domain->create_proxy_for_type_method = im;
4383 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4385 o = mono_runtime_invoke (im, NULL, pa, NULL);
4386 if (o != NULL) return o;
4389 return mono_object_new_alloc_specific (vtable);
4393 mono_object_new_alloc_specific (MonoVTable *vtable)
4397 if (!vtable->klass->has_references) {
4398 o = mono_object_new_ptrfree (vtable);
4399 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4400 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4402 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4403 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4405 if (G_UNLIKELY (vtable->klass->has_finalize))
4406 mono_object_register_finalizer (o);
4408 if (G_UNLIKELY (profile_allocs))
4409 mono_profiler_allocation (o, vtable->klass);
4414 mono_object_new_fast (MonoVTable *vtable)
4417 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4422 mono_object_new_ptrfree (MonoVTable *vtable)
4425 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4426 #if NEED_TO_ZERO_PTRFREE
4427 /* an inline memset is much faster for the common vcase of small objects
4428 * note we assume the allocated size is a multiple of sizeof (void*).
4430 if (vtable->klass->instance_size < 128) {
4432 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4433 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4439 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4446 mono_object_new_ptrfree_box (MonoVTable *vtable)
4449 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4450 /* the object will be boxed right away, no need to memzero it */
4455 * mono_class_get_allocation_ftn:
4457 * @for_box: the object will be used for boxing
4458 * @pass_size_in_words:
4460 * Return the allocation function appropriate for the given class.
4464 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4466 *pass_size_in_words = FALSE;
4468 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4469 profile_allocs = FALSE;
4471 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4472 return mono_object_new_specific;
4474 if (!vtable->klass->has_references) {
4475 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4477 return mono_object_new_ptrfree_box;
4478 return mono_object_new_ptrfree;
4481 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4483 return mono_object_new_fast;
4486 * FIXME: This is actually slower than mono_object_new_fast, because
4487 * of the overhead of parameter passing.
4490 *pass_size_in_words = TRUE;
4491 #ifdef GC_REDIRECT_TO_LOCAL
4492 return GC_local_gcj_fast_malloc;
4494 return GC_gcj_fast_malloc;
4499 return mono_object_new_specific;
4503 * mono_object_new_from_token:
4504 * @image: Context where the type_token is hosted
4505 * @token: a token of the type that we want to create
4507 * Returns: A newly created object whose definition is
4508 * looked up using @token in the @image image
4511 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4515 class = mono_class_get (image, token);
4517 return mono_object_new (domain, class);
4522 * mono_object_clone:
4523 * @obj: the object to clone
4525 * Returns: A newly created object who is a shallow copy of @obj
4528 mono_object_clone (MonoObject *obj)
4531 int size = obj->vtable->klass->instance_size;
4533 if (obj->vtable->klass->rank)
4534 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4536 o = mono_object_allocate (size, obj->vtable);
4538 if (obj->vtable->klass->has_references) {
4539 mono_gc_wbarrier_object_copy (o, obj);
4541 int size = obj->vtable->klass->instance_size;
4542 /* do not copy the sync state */
4543 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4545 if (G_UNLIKELY (profile_allocs))
4546 mono_profiler_allocation (o, obj->vtable->klass);
4548 if (obj->vtable->klass->has_finalize)
4549 mono_object_register_finalizer (o);
4554 * mono_array_full_copy:
4555 * @src: source array to copy
4556 * @dest: destination array
4558 * Copies the content of one array to another with exactly the same type and size.
4561 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4564 MonoClass *klass = src->obj.vtable->klass;
4566 MONO_ARCH_SAVE_REGS;
4568 g_assert (klass == dest->obj.vtable->klass);
4570 size = mono_array_length (src);
4571 g_assert (size == mono_array_length (dest));
4572 size *= mono_array_element_size (klass);
4574 if (klass->element_class->valuetype) {
4575 if (klass->element_class->has_references)
4576 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4578 mono_gc_memmove (&dest->vector, &src->vector, size);
4580 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4583 mono_gc_memmove (&dest->vector, &src->vector, size);
4588 * mono_array_clone_in_domain:
4589 * @domain: the domain in which the array will be cloned into
4590 * @array: the array to clone
4592 * This routine returns a copy of the array that is hosted on the
4593 * specified MonoDomain.
4596 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4601 MonoClass *klass = array->obj.vtable->klass;
4603 MONO_ARCH_SAVE_REGS;
4605 if (array->bounds == NULL) {
4606 size = mono_array_length (array);
4607 o = mono_array_new_full (domain, klass, &size, NULL);
4609 size *= mono_array_element_size (klass);
4611 if (klass->element_class->valuetype) {
4612 if (klass->element_class->has_references)
4613 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4615 mono_gc_memmove (&o->vector, &array->vector, size);
4617 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4620 mono_gc_memmove (&o->vector, &array->vector, size);
4625 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4626 size = mono_array_element_size (klass);
4627 for (i = 0; i < klass->rank; ++i) {
4628 sizes [i] = array->bounds [i].length;
4629 size *= array->bounds [i].length;
4630 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4632 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4634 if (klass->element_class->valuetype) {
4635 if (klass->element_class->has_references)
4636 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4638 mono_gc_memmove (&o->vector, &array->vector, size);
4640 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4643 mono_gc_memmove (&o->vector, &array->vector, size);
4651 * @array: the array to clone
4653 * Returns: A newly created array who is a shallow copy of @array
4656 mono_array_clone (MonoArray *array)
4658 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4661 /* helper macros to check for overflow when calculating the size of arrays */
4662 #ifdef MONO_BIG_ARRAYS
4663 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4664 #define MYGUINT_MAX MYGUINT64_MAX
4665 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4666 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4667 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4668 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4669 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4671 #define MYGUINT32_MAX 4294967295U
4672 #define MYGUINT_MAX MYGUINT32_MAX
4673 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4674 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4675 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4676 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4677 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4681 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4685 byte_len = mono_array_element_size (class);
4686 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4689 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4691 byte_len += sizeof (MonoArray);
4699 * mono_array_new_full:
4700 * @domain: domain where the object is created
4701 * @array_class: array class
4702 * @lengths: lengths for each dimension in the array
4703 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4705 * This routine creates a new array objects with the given dimensions,
4706 * lower bounds and type.
4709 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4711 uintptr_t byte_len, len, bounds_size;
4714 MonoArrayBounds *bounds;
4718 if (!array_class->inited)
4719 mono_class_init (array_class);
4723 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4724 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4726 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4730 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4732 for (i = 0; i < array_class->rank; ++i) {
4733 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4735 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4736 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4741 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4742 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4746 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4747 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4748 byte_len = (byte_len + 3) & ~3;
4749 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4750 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4751 byte_len += bounds_size;
4754 * Following three lines almost taken from mono_object_new ():
4755 * they need to be kept in sync.
4757 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4758 #ifndef HAVE_SGEN_GC
4759 if (!array_class->has_references) {
4760 o = mono_object_allocate_ptrfree (byte_len, vtable);
4761 #if NEED_TO_ZERO_PTRFREE
4762 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4764 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4765 o = mono_object_allocate_spec (byte_len, vtable);
4767 o = mono_object_allocate (byte_len, vtable);
4770 array = (MonoArray*)o;
4771 array->max_length = len;
4774 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4775 array->bounds = bounds;
4779 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4781 o = mono_gc_alloc_vector (vtable, byte_len, len);
4782 array = (MonoArray*)o;
4783 mono_stats.new_object_count++;
4785 bounds = array->bounds;
4789 for (i = 0; i < array_class->rank; ++i) {
4790 bounds [i].length = lengths [i];
4792 bounds [i].lower_bound = lower_bounds [i];
4796 if (G_UNLIKELY (profile_allocs))
4797 mono_profiler_allocation (o, array_class);
4804 * @domain: domain where the object is created
4805 * @eclass: element class
4806 * @n: number of array elements
4808 * This routine creates a new szarray with @n elements of type @eclass.
4811 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4815 MONO_ARCH_SAVE_REGS;
4817 ac = mono_array_class_get (eclass, 1);
4820 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4824 * mono_array_new_specific:
4825 * @vtable: a vtable in the appropriate domain for an initialized class
4826 * @n: number of array elements
4828 * This routine is a fast alternative to mono_array_new() for code which
4829 * can be sure about the domain it operates in.
4832 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4838 MONO_ARCH_SAVE_REGS;
4840 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4845 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4846 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4849 #ifndef HAVE_SGEN_GC
4850 if (!vtable->klass->has_references) {
4851 o = mono_object_allocate_ptrfree (byte_len, vtable);
4852 #if NEED_TO_ZERO_PTRFREE
4853 ((MonoArray*)o)->bounds = NULL;
4854 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4856 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4857 o = mono_object_allocate_spec (byte_len, vtable);
4859 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4860 o = mono_object_allocate (byte_len, vtable);
4863 ao = (MonoArray *)o;
4866 o = mono_gc_alloc_vector (vtable, byte_len, n);
4868 mono_stats.new_object_count++;
4871 if (G_UNLIKELY (profile_allocs))
4872 mono_profiler_allocation (o, vtable->klass);
4878 * mono_string_new_utf16:
4879 * @text: a pointer to an utf16 string
4880 * @len: the length of the string
4882 * Returns: A newly created string object which contains @text.
4885 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4889 s = mono_string_new_size (domain, len);
4890 g_assert (s != NULL);
4892 memcpy (mono_string_chars (s), text, len * 2);
4898 * mono_string_new_size:
4899 * @text: a pointer to an utf16 string
4900 * @len: the length of the string
4902 * Returns: A newly created string object of @len
4905 mono_string_new_size (MonoDomain *domain, gint32 len)
4909 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4911 /* overflow ? can't fit it, can't allocate it! */
4913 mono_gc_out_of_memory (-1);
4915 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4918 #ifndef HAVE_SGEN_GC
4919 s = mono_object_allocate_ptrfree (size, vtable);
4923 s = mono_gc_alloc_string (vtable, size, len);
4925 #if NEED_TO_ZERO_PTRFREE
4928 if (G_UNLIKELY (profile_allocs))
4929 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4935 * mono_string_new_len:
4936 * @text: a pointer to an utf8 string
4937 * @length: number of bytes in @text to consider
4939 * Returns: A newly created string object which contains @text.
4942 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4944 GError *error = NULL;
4945 MonoString *o = NULL;
4947 glong items_written;
4949 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
4952 o = mono_string_new_utf16 (domain, ut, items_written);
4954 g_error_free (error);
4963 * @text: a pointer to an utf8 string
4965 * Returns: A newly created string object which contains @text.
4968 mono_string_new (MonoDomain *domain, const char *text)
4970 GError *error = NULL;
4971 MonoString *o = NULL;
4973 glong items_written;
4978 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4981 o = mono_string_new_utf16 (domain, ut, items_written);
4983 g_error_free (error);
4986 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4991 MonoString *o = NULL;
4993 if (!g_utf8_validate (text, -1, &end))
4996 len = g_utf8_strlen (text, -1);
4997 o = mono_string_new_size (domain, len);
4998 str = mono_string_chars (o);
5000 while (text < end) {
5001 *str++ = g_utf8_get_char (text);
5002 text = g_utf8_next_char (text);
5009 * mono_string_new_wrapper:
5010 * @text: pointer to utf8 characters.
5012 * Helper function to create a string object from @text in the current domain.
5015 mono_string_new_wrapper (const char *text)
5017 MonoDomain *domain = mono_domain_get ();
5019 MONO_ARCH_SAVE_REGS;
5022 return mono_string_new (domain, text);
5029 * @class: the class of the value
5030 * @value: a pointer to the unboxed data
5032 * Returns: A newly created object which contains @value.
5035 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5041 g_assert (class->valuetype);
5042 if (mono_class_is_nullable (class))
5043 return mono_nullable_box (value, class);
5045 vtable = mono_class_vtable (domain, class);
5048 size = mono_class_instance_size (class);
5049 res = mono_object_new_alloc_specific (vtable);
5050 if (G_UNLIKELY (profile_allocs))
5051 mono_profiler_allocation (res, class);
5053 size = size - sizeof (MonoObject);
5056 g_assert (size == mono_class_value_size (class, NULL));
5057 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5059 #if NO_UNALIGNED_ACCESS
5060 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5064 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5067 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5070 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5073 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5076 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5080 if (class->has_finalize)
5081 mono_object_register_finalizer (res);
5087 * @dest: destination pointer
5088 * @src: source pointer
5089 * @klass: a valuetype class
5091 * Copy a valuetype from @src to @dest. This function must be used
5092 * when @klass contains references fields.
5095 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5097 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5101 * mono_value_copy_array:
5102 * @dest: destination array
5103 * @dest_idx: index in the @dest array
5104 * @src: source pointer
5105 * @count: number of items
5107 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5108 * This function must be used when @klass contains references fields.
5109 * Overlap is handled.
5112 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5114 int size = mono_array_element_size (dest->obj.vtable->klass);
5115 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5116 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5117 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5121 * mono_object_get_domain:
5122 * @obj: object to query
5124 * Returns: the MonoDomain where the object is hosted
5127 mono_object_get_domain (MonoObject *obj)
5129 return mono_object_domain (obj);
5133 * mono_object_get_class:
5134 * @obj: object to query
5136 * Returns: the MonOClass of the object.
5139 mono_object_get_class (MonoObject *obj)
5141 return mono_object_class (obj);
5144 * mono_object_get_size:
5145 * @o: object to query
5147 * Returns: the size, in bytes, of @o
5150 mono_object_get_size (MonoObject* o)
5152 MonoClass* klass = mono_object_class (o);
5153 if (klass == mono_defaults.string_class) {
5154 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5155 } else if (o->vtable->rank) {
5156 MonoArray *array = (MonoArray*)o;
5157 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5158 if (array->bounds) {
5161 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5165 return mono_class_instance_size (klass);
5170 * mono_object_unbox:
5171 * @obj: object to unbox
5173 * Returns: a pointer to the start of the valuetype boxed in this
5176 * This method will assert if the object passed is not a valuetype.
5179 mono_object_unbox (MonoObject *obj)
5181 /* add assert for valuetypes? */
5182 g_assert (obj->vtable->klass->valuetype);
5183 return ((char*)obj) + sizeof (MonoObject);
5187 * mono_object_isinst:
5189 * @klass: a pointer to a class
5191 * Returns: @obj if @obj is derived from @klass
5194 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5197 mono_class_init (klass);
5199 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5200 return mono_object_isinst_mbyref (obj, klass);
5205 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5209 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5218 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5219 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5223 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5224 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5227 MonoClass *oklass = vt->klass;
5228 if (oklass == mono_defaults.transparent_proxy_class)
5229 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5231 mono_class_setup_supertypes (klass);
5232 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5236 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5238 MonoDomain *domain = mono_domain_get ();
5240 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5241 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5242 MonoMethod *im = NULL;
5245 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5246 im = mono_object_get_virtual_method (rp, im);
5249 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5252 res = mono_runtime_invoke (im, rp, pa, NULL);
5254 if (*(MonoBoolean *) mono_object_unbox(res)) {
5255 /* Update the vtable of the remote type, so it can safely cast to this new type */
5256 mono_upgrade_remote_class (domain, obj, klass);
5265 * mono_object_castclass_mbyref:
5267 * @klass: a pointer to a class
5269 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5272 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5274 if (!obj) return NULL;
5275 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5277 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5279 "InvalidCastException"));
5284 MonoDomain *orig_domain;
5290 str_lookup (MonoDomain *domain, gpointer user_data)
5292 LDStrInfo *info = user_data;
5293 if (info->res || domain == info->orig_domain)
5295 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5301 mono_string_get_pinned (MonoString *str)
5305 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5306 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5308 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5309 news->length = mono_string_length (str);
5315 #define mono_string_get_pinned(str) (str)
5319 mono_string_is_interned_lookup (MonoString *str, int insert)
5321 MonoGHashTable *ldstr_table;
5325 domain = ((MonoObject *)str)->vtable->domain;
5326 ldstr_table = domain->ldstr_table;
5328 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5333 str = mono_string_get_pinned (str);
5335 mono_g_hash_table_insert (ldstr_table, str, str);
5339 LDStrInfo ldstr_info;
5340 ldstr_info.orig_domain = domain;
5341 ldstr_info.ins = str;
5342 ldstr_info.res = NULL;
5344 mono_domain_foreach (str_lookup, &ldstr_info);
5345 if (ldstr_info.res) {
5347 * the string was already interned in some other domain:
5348 * intern it in the current one as well.
5350 mono_g_hash_table_insert (ldstr_table, str, str);
5360 * mono_string_is_interned:
5361 * @o: String to probe
5363 * Returns whether the string has been interned.
5366 mono_string_is_interned (MonoString *o)
5368 return mono_string_is_interned_lookup (o, FALSE);
5372 * mono_string_intern:
5373 * @o: String to intern
5375 * Interns the string passed.
5376 * Returns: The interned string.
5379 mono_string_intern (MonoString *str)
5381 return mono_string_is_interned_lookup (str, TRUE);
5386 * @domain: the domain where the string will be used.
5387 * @image: a metadata context
5388 * @idx: index into the user string table.
5390 * Implementation for the ldstr opcode.
5391 * Returns: a loaded string from the @image/@idx combination.
5394 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5396 MONO_ARCH_SAVE_REGS;
5398 if (image->dynamic) {
5399 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5402 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5403 return NULL; /*FIXME we should probably be raising an exception here*/
5404 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5409 * mono_ldstr_metadata_sig
5410 * @domain: the domain for the string
5411 * @sig: the signature of a metadata string
5413 * Returns: a MonoString for a string stored in the metadata
5416 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5418 const char *str = sig;
5419 MonoString *o, *interned;
5422 len2 = mono_metadata_decode_blob_size (str, &str);
5425 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5426 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5429 guint16 *p2 = (guint16*)mono_string_chars (o);
5430 for (i = 0; i < len2; ++i) {
5431 *p2 = GUINT16_FROM_LE (*p2);
5437 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5439 /* o will get garbage collected */
5443 o = mono_string_get_pinned (o);
5445 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5452 * mono_string_to_utf8:
5453 * @s: a System.String
5455 * Returns the UTF8 representation for @s.
5456 * The resulting buffer needs to be freed with mono_free().
5458 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5461 mono_string_to_utf8 (MonoString *s)
5464 char *result = mono_string_to_utf8_checked (s, &error);
5466 if (!mono_error_ok (&error))
5467 mono_error_raise_exception (&error);
5472 * mono_string_to_utf8_checked:
5473 * @s: a System.String
5474 * @error: a MonoError.
5476 * Converts a MonoString to its UTF8 representation. May fail; check
5477 * @error to determine whether the conversion was successful.
5478 * The resulting buffer should be freed with mono_free().
5481 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5485 GError *gerror = NULL;
5487 mono_error_init (error);
5493 return g_strdup ("");
5495 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5497 mono_error_set_argument (error, "string", "%s", gerror->message);
5498 g_error_free (gerror);
5501 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5502 if (s->length > written) {
5503 /* allocate the total length and copy the part of the string that has been converted */
5504 char *as2 = g_malloc0 (s->length);
5505 memcpy (as2, as, written);
5514 * mono_string_to_utf8_ignore:
5517 * Converts a MonoString to its UTF8 representation. Will ignore
5518 * invalid surrogate pairs.
5519 * The resulting buffer should be freed with mono_free().
5523 mono_string_to_utf8_ignore (MonoString *s)
5532 return g_strdup ("");
5534 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5536 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5537 if (s->length > written) {
5538 /* allocate the total length and copy the part of the string that has been converted */
5539 char *as2 = g_malloc0 (s->length);
5540 memcpy (as2, as, written);
5549 * mono_string_to_utf8_image_ignore:
5550 * @s: a System.String
5552 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5555 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5557 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5561 * mono_string_to_utf8_mp_ignore:
5562 * @s: a System.String
5564 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5567 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5569 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5574 * mono_string_to_utf16:
5577 * Return an null-terminated array of the utf-16 chars
5578 * contained in @s. The result must be freed with g_free().
5579 * This is a temporary helper until our string implementation
5580 * is reworked to always include the null terminating char.
5583 mono_string_to_utf16 (MonoString *s)
5590 as = g_malloc ((s->length * 2) + 2);
5591 as [(s->length * 2)] = '\0';
5592 as [(s->length * 2) + 1] = '\0';
5595 return (gunichar2 *)(as);
5598 memcpy (as, mono_string_chars(s), s->length * 2);
5599 return (gunichar2 *)(as);
5603 * mono_string_from_utf16:
5604 * @data: the UTF16 string (LPWSTR) to convert
5606 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5608 * Returns: a MonoString.
5611 mono_string_from_utf16 (gunichar2 *data)
5613 MonoDomain *domain = mono_domain_get ();
5619 while (data [len]) len++;
5621 return mono_string_new_utf16 (domain, data, len);
5626 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5633 r = mono_string_to_utf8_ignore (s);
5635 r = mono_string_to_utf8_checked (s, error);
5636 if (!mono_error_ok (error))
5643 len = strlen (r) + 1;
5645 mp_s = mono_mempool_alloc (mp, len);
5647 mp_s = mono_image_alloc (image, len);
5649 memcpy (mp_s, r, len);
5657 * mono_string_to_utf8_image:
5658 * @s: a System.String
5660 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5663 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5665 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5669 * mono_string_to_utf8_mp:
5670 * @s: a System.String
5672 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5675 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5677 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5681 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5684 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5686 eh_callbacks = *cbs;
5689 MonoRuntimeExceptionHandlingCallbacks *
5690 mono_get_eh_callbacks (void)
5692 return &eh_callbacks;
5696 * mono_raise_exception:
5697 * @ex: exception object
5699 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5702 mono_raise_exception (MonoException *ex)
5705 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5706 * that will cause gcc to omit the function epilog, causing problems when
5707 * the JIT tries to walk the stack, since the return address on the stack
5708 * will point into the next function in the executable, not this one.
5710 eh_callbacks.mono_raise_exception (ex);
5714 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5716 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5720 * mono_wait_handle_new:
5721 * @domain: Domain where the object will be created
5722 * @handle: Handle for the wait handle
5724 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5727 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5729 MonoWaitHandle *res;
5730 gpointer params [1];
5731 static MonoMethod *handle_set;
5733 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5735 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5737 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5739 params [0] = &handle;
5740 mono_runtime_invoke (handle_set, res, params, NULL);
5746 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5748 static MonoClassField *f_os_handle;
5749 static MonoClassField *f_safe_handle;
5751 if (!f_os_handle && !f_safe_handle) {
5752 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5753 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5758 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5762 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5769 mono_runtime_capture_context (MonoDomain *domain)
5771 RuntimeInvokeFunction runtime_invoke;
5773 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5774 MonoMethod *method = mono_get_context_capture_method ();
5775 MonoMethod *wrapper;
5778 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5779 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5780 domain->capture_context_method = mono_compile_method (method);
5783 runtime_invoke = domain->capture_context_runtime_invoke;
5785 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5788 * mono_async_result_new:
5789 * @domain:domain where the object will be created.
5790 * @handle: wait handle.
5791 * @state: state to pass to AsyncResult
5792 * @data: C closure data.
5794 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5795 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5799 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5801 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5802 MonoObject *context = mono_runtime_capture_context (domain);
5803 /* we must capture the execution context from the original thread */
5805 MONO_OBJECT_SETREF (res, execution_context, context);
5806 /* note: result may be null if the flow is suppressed */
5810 MONO_OBJECT_SETREF (res, object_data, object_data);
5811 MONO_OBJECT_SETREF (res, async_state, state);
5813 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5815 res->sync_completed = FALSE;
5816 res->completed = FALSE;
5822 mono_message_init (MonoDomain *domain,
5823 MonoMethodMessage *this,
5824 MonoReflectionMethod *method,
5825 MonoArray *out_args)
5827 static MonoClass *object_array_klass;
5828 static MonoClass *byte_array_klass;
5829 static MonoClass *string_array_klass;
5830 MonoMethodSignature *sig = mono_method_signature (method->method);
5836 if (!object_array_klass) {
5839 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5841 byte_array_klass = klass;
5843 klass = mono_array_class_get (mono_defaults.string_class, 1);
5845 string_array_klass = klass;
5847 klass = mono_array_class_get (mono_defaults.object_class, 1);
5850 mono_atomic_store_release (&object_array_klass, klass);
5853 MONO_OBJECT_SETREF (this, method, method);
5855 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5856 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5857 this->async_result = NULL;
5858 this->call_type = CallType_Sync;
5860 names = g_new (char *, sig->param_count);
5861 mono_method_get_param_names (method->method, (const char **) names);
5862 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5864 for (i = 0; i < sig->param_count; i++) {
5865 name = mono_string_new (domain, names [i]);
5866 mono_array_setref (this->names, i, name);
5870 for (i = 0, j = 0; i < sig->param_count; i++) {
5871 if (sig->params [i]->byref) {
5873 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5874 mono_array_setref (this->args, i, arg);
5878 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5882 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5885 mono_array_set (this->arg_types, guint8, i, arg_type);
5890 * mono_remoting_invoke:
5891 * @real_proxy: pointer to a RealProxy object
5892 * @msg: The MonoMethodMessage to execute
5893 * @exc: used to store exceptions
5894 * @out_args: used to store output arguments
5896 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5897 * IMessage interface and it is not trivial to extract results from there. So
5898 * we call an helper method PrivateInvoke instead of calling
5899 * RealProxy::Invoke() directly.
5901 * Returns: the result object.
5904 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5905 MonoObject **exc, MonoArray **out_args)
5907 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5910 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5913 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5915 real_proxy->vtable->domain->private_invoke_method = im;
5918 pa [0] = real_proxy;
5923 return mono_runtime_invoke (im, NULL, pa, exc);
5927 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5928 MonoObject **exc, MonoArray **out_args)
5930 static MonoClass *object_array_klass;
5933 MonoMethodSignature *sig;
5935 int i, j, outarg_count = 0;
5937 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5939 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5940 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5941 target = tp->rp->unwrapped_server;
5943 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5947 domain = mono_domain_get ();
5948 method = msg->method->method;
5949 sig = mono_method_signature (method);
5951 for (i = 0; i < sig->param_count; i++) {
5952 if (sig->params [i]->byref)
5956 if (!object_array_klass) {
5959 klass = mono_array_class_get (mono_defaults.object_class, 1);
5962 mono_memory_barrier ();
5963 object_array_klass = klass;
5966 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5967 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5970 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5972 for (i = 0, j = 0; i < sig->param_count; i++) {
5973 if (sig->params [i]->byref) {
5975 arg = mono_array_get (msg->args, gpointer, i);
5976 mono_array_setref (*out_args, j, arg);
5985 * mono_object_to_string:
5987 * @exc: Any exception thrown by ToString (). May be NULL.
5989 * Returns: the result of calling ToString () on an object.
5992 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5994 static MonoMethod *to_string = NULL;
6000 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6002 method = mono_object_get_virtual_method (obj, to_string);
6004 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
6008 * mono_print_unhandled_exception:
6009 * @exc: The exception
6011 * Prints the unhandled exception.
6014 mono_print_unhandled_exception (MonoObject *exc)
6017 char *message = (char*)"";
6018 gboolean free_message = FALSE;
6021 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6022 message = g_strdup ("OutOfMemoryException");
6023 free_message = TRUE;
6026 if (((MonoException*)exc)->native_trace_ips) {
6027 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6028 free_message = TRUE;
6030 str = mono_object_to_string (exc, NULL);
6032 message = mono_string_to_utf8_checked (str, &error);
6033 if (!mono_error_ok (&error)) {
6034 mono_error_cleanup (&error);
6035 message = (char *) "";
6037 free_message = TRUE;
6044 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6045 * exc->vtable->klass->name, message);
6047 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6054 * mono_delegate_ctor:
6055 * @this: pointer to an uninitialized delegate object
6056 * @target: target object
6057 * @addr: pointer to native code
6060 * Initialize a delegate and sets a specific method, not the one
6061 * associated with addr. This is useful when sharing generic code.
6062 * In that case addr will most probably not be associated with the
6063 * correct instantiation of the method.
6066 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6068 MonoDelegate *delegate = (MonoDelegate *)this;
6075 delegate->method = method;
6077 class = this->vtable->klass;
6078 mono_stats.delegate_creations++;
6080 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6082 method = mono_marshal_get_remoting_invoke (method);
6083 delegate->method_ptr = mono_compile_method (method);
6084 MONO_OBJECT_SETREF (delegate, target, target);
6085 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6086 method = mono_marshal_get_unbox_wrapper (method);
6087 delegate->method_ptr = mono_compile_method (method);
6088 MONO_OBJECT_SETREF (delegate, target, target);
6090 delegate->method_ptr = addr;
6091 MONO_OBJECT_SETREF (delegate, target, target);
6094 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6098 * mono_delegate_ctor:
6099 * @this: pointer to an uninitialized delegate object
6100 * @target: target object
6101 * @addr: pointer to native code
6103 * This is used to initialize a delegate.
6106 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6108 MonoDomain *domain = mono_domain_get ();
6110 MonoMethod *method = NULL;
6114 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6116 if (!ji && domain != mono_get_root_domain ())
6117 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6119 method = ji->method;
6120 g_assert (!method->klass->generic_container);
6123 mono_delegate_ctor_with_method (this, target, addr, method);
6127 * mono_method_call_message_new:
6128 * @method: method to encapsulate
6129 * @params: parameters to the method
6130 * @invoke: optional, delegate invoke.
6131 * @cb: async callback delegate.
6132 * @state: state passed to the async callback.
6134 * Translates arguments pointers into a MonoMethodMessage.
6137 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6138 MonoDelegate **cb, MonoObject **state)
6140 MonoDomain *domain = mono_domain_get ();
6141 MonoMethodSignature *sig = mono_method_signature (method);
6142 MonoMethodMessage *msg;
6145 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6148 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6149 count = sig->param_count - 2;
6151 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6152 count = sig->param_count;
6155 for (i = 0; i < count; i++) {
6160 if (sig->params [i]->byref)
6161 vpos = *((gpointer *)params [i]);
6165 type = sig->params [i]->type;
6166 class = mono_class_from_mono_type (sig->params [i]);
6168 if (class->valuetype)
6169 arg = mono_value_box (domain, class, vpos);
6171 arg = *((MonoObject **)vpos);
6173 mono_array_setref (msg->args, i, arg);
6176 if (cb != NULL && state != NULL) {
6177 *cb = *((MonoDelegate **)params [i]);
6179 *state = *((MonoObject **)params [i]);
6186 * mono_method_return_message_restore:
6188 * Restore results from message based processing back to arguments pointers
6191 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6193 MonoMethodSignature *sig = mono_method_signature (method);
6194 int i, j, type, size, out_len;
6196 if (out_args == NULL)
6198 out_len = mono_array_length (out_args);
6202 for (i = 0, j = 0; i < sig->param_count; i++) {
6203 MonoType *pt = sig->params [i];
6208 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6210 arg = mono_array_get (out_args, gpointer, j);
6213 g_assert (type != MONO_TYPE_VOID);
6215 if (MONO_TYPE_IS_REFERENCE (pt)) {
6216 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6219 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6220 size = mono_class_value_size (class, NULL);
6221 if (class->has_references)
6222 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6224 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6226 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6227 mono_gc_bzero (*((gpointer *)params [i]), size);
6237 * mono_load_remote_field:
6238 * @this: pointer to an object
6239 * @klass: klass of the object containing @field
6240 * @field: the field to load
6241 * @res: a storage to store the result
6243 * This method is called by the runtime on attempts to load fields of
6244 * transparent proxy objects. @this points to such TP, @klass is the class of
6245 * the object containing @field. @res is a storage location which can be
6246 * used to store the result.
6248 * Returns: an address pointing to the value of field.
6251 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6253 static MonoMethod *getter = NULL;
6254 MonoDomain *domain = mono_domain_get ();
6255 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6256 MonoClass *field_class;
6257 MonoMethodMessage *msg;
6258 MonoArray *out_args;
6262 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6263 g_assert (res != NULL);
6265 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6266 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6271 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6275 field_class = mono_class_from_mono_type (field->type);
6277 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6278 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6279 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6281 full_name = mono_type_get_full_name (klass);
6282 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6283 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6286 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6288 if (exc) mono_raise_exception ((MonoException *)exc);
6290 if (mono_array_length (out_args) == 0)
6293 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6295 if (field_class->valuetype) {
6296 return ((char *)*res) + sizeof (MonoObject);
6302 * mono_load_remote_field_new:
6307 * Missing documentation.
6310 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6312 static MonoMethod *getter = NULL;
6313 MonoDomain *domain = mono_domain_get ();
6314 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6315 MonoClass *field_class;
6316 MonoMethodMessage *msg;
6317 MonoArray *out_args;
6318 MonoObject *exc, *res;
6321 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6323 field_class = mono_class_from_mono_type (field->type);
6325 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6327 if (field_class->valuetype) {
6328 res = mono_object_new (domain, field_class);
6329 val = ((gchar *) res) + sizeof (MonoObject);
6333 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6338 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6342 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6343 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6345 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6347 full_name = mono_type_get_full_name (klass);
6348 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6349 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6352 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6354 if (exc) mono_raise_exception ((MonoException *)exc);
6356 if (mono_array_length (out_args) == 0)
6359 res = mono_array_get (out_args, MonoObject *, 0);
6365 * mono_store_remote_field:
6366 * @this: pointer to an object
6367 * @klass: klass of the object containing @field
6368 * @field: the field to load
6369 * @val: the value/object to store
6371 * This method is called by the runtime on attempts to store fields of
6372 * transparent proxy objects. @this points to such TP, @klass is the class of
6373 * the object containing @field. @val is the new value to store in @field.
6376 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6378 static MonoMethod *setter = NULL;
6379 MonoDomain *domain = mono_domain_get ();
6380 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6381 MonoClass *field_class;
6382 MonoMethodMessage *msg;
6383 MonoArray *out_args;
6388 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6390 field_class = mono_class_from_mono_type (field->type);
6392 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6393 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6394 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6399 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6403 if (field_class->valuetype)
6404 arg = mono_value_box (domain, field_class, val);
6406 arg = *((MonoObject **)val);
6409 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6410 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6412 full_name = mono_type_get_full_name (klass);
6413 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6414 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6415 mono_array_setref (msg->args, 2, arg);
6418 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6420 if (exc) mono_raise_exception ((MonoException *)exc);
6424 * mono_store_remote_field_new:
6430 * Missing documentation
6433 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6435 static MonoMethod *setter = NULL;
6436 MonoDomain *domain = mono_domain_get ();
6437 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6438 MonoClass *field_class;
6439 MonoMethodMessage *msg;
6440 MonoArray *out_args;
6444 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6446 field_class = mono_class_from_mono_type (field->type);
6448 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6449 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6450 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6455 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6459 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6460 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6462 full_name = mono_type_get_full_name (klass);
6463 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6464 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6465 mono_array_setref (msg->args, 2, arg);
6468 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6470 if (exc) mono_raise_exception ((MonoException *)exc);
6474 * mono_create_ftnptr:
6476 * Given a function address, create a function descriptor for it.
6477 * This is only needed on some platforms.
6480 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6482 return callbacks.create_ftnptr (domain, addr);
6486 * mono_get_addr_from_ftnptr:
6488 * Given a pointer to a function descriptor, return the function address.
6489 * This is only needed on some platforms.
6492 mono_get_addr_from_ftnptr (gpointer descr)
6494 return callbacks.get_addr_from_ftnptr (descr);
6498 * mono_string_chars:
6501 * Returns a pointer to the UCS16 characters stored in the MonoString
6504 mono_string_chars (MonoString *s)
6510 * mono_string_length:
6513 * Returns the lenght in characters of the string
6516 mono_string_length (MonoString *s)
6522 * mono_array_length:
6523 * @array: a MonoArray*
6525 * Returns the total number of elements in the array. This works for
6526 * both vectors and multidimensional arrays.
6529 mono_array_length (MonoArray *array)
6531 return array->max_length;
6535 * mono_array_addr_with_size:
6536 * @array: a MonoArray*
6537 * @size: size of the array elements
6538 * @idx: index into the array
6540 * Returns the address of the @idx element in the array.
6543 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6545 return ((char*)(array)->vector) + size * idx;