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};
2003 if (mono_type_is_reference (field->type)) {
2004 default_bitmap [0] = 1;
2006 bitmap = default_bitmap;
2007 } else if (mono_type_is_struct (field->type)) {
2008 fclass = mono_class_from_mono_type (field->type);
2009 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2011 default_bitmap [0] = 0;
2013 bitmap = default_bitmap;
2015 size = mono_type_size (field->type, &align);
2016 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2017 if (!domain->special_static_fields)
2018 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2019 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2020 if (bitmap != default_bitmap)
2023 * This marks the field as special static to speed up the
2024 * checks in mono_field_static_get/set_value ().
2030 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2031 MonoClass *fklass = mono_class_from_mono_type (field->type);
2032 const char *data = mono_field_get_data (field);
2034 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2035 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2036 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2039 if (fklass->valuetype) {
2040 memcpy (t, data, mono_class_value_size (fklass, NULL));
2042 /* it's a pointer type: add check */
2043 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2050 vt->max_interface_id = class->max_interface_id;
2051 vt->interface_bitmap = class->interface_bitmap;
2053 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2054 // class->name, class->interface_offsets_count);
2056 if (! ARCH_USE_IMT) {
2057 /* initialize interface offsets */
2058 for (i = 0; i < class->interface_offsets_count; ++i) {
2059 int interface_id = class->interfaces_packed [i]->interface_id;
2060 int slot = class->interface_offsets_packed [i];
2061 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2065 /* Initialize vtable */
2066 if (callbacks.get_vtable_trampoline) {
2067 // This also covers the AOT case
2068 for (i = 0; i < class->vtable_size; ++i) {
2069 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2072 mono_class_setup_vtable (class);
2074 for (i = 0; i < class->vtable_size; ++i) {
2077 if ((cm = class->vtable [i]))
2078 vt->vtable [i] = arch_create_jit_trampoline (cm);
2082 if (ARCH_USE_IMT && imt_table_bytes) {
2083 /* Now that the vtable is full, we can actually fill up the IMT */
2084 if (callbacks.get_imt_trampoline) {
2085 /* lazy construction of the IMT entries enabled */
2086 for (i = 0; i < MONO_IMT_SIZE; ++i)
2087 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2089 build_imt (class, vt, domain, interface_offsets, NULL);
2094 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2095 * re-acquire them and check if another thread has created the vtable in the meantime.
2097 /* Special case System.MonoType to avoid infinite recursion */
2098 if (class != mono_defaults.monotype_class) {
2099 /*FIXME check for OOM*/
2100 vt->type = mono_type_get_object (domain, &class->byval_arg);
2101 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2102 /* This is unregistered in
2103 unregister_vtable_reflection_type() in
2105 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2108 if (class->contextbound)
2113 /* class_vtable_array keeps an array of created vtables
2115 g_ptr_array_add (domain->class_vtable_array, vt);
2116 /* class->runtime_info is protected by the loader lock, both when
2117 * it it enlarged and when it is stored info.
2121 * Store the vtable in class->runtime_info.
2122 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2124 mono_memory_barrier ();
2126 old_info = class->runtime_info;
2127 if (old_info && old_info->max_domain >= domain->domain_id) {
2128 /* someone already created a large enough runtime info */
2129 old_info->domain_vtables [domain->domain_id] = vt;
2131 int new_size = domain->domain_id;
2133 new_size = MAX (new_size, old_info->max_domain);
2135 /* make the new size a power of two */
2137 while (new_size > i)
2140 /* this is a bounded memory retention issue: may want to
2141 * handle it differently when we'll have a rcu-like system.
2143 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2144 runtime_info->max_domain = new_size - 1;
2145 /* copy the stuff from the older info */
2147 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2149 runtime_info->domain_vtables [domain->domain_id] = vt;
2151 mono_memory_barrier ();
2152 class->runtime_info = runtime_info;
2155 if (class == mono_defaults.monotype_class) {
2156 /*FIXME check for OOM*/
2157 vt->type = mono_type_get_object (domain, &class->byval_arg);
2158 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2159 /* This is unregistered in
2160 unregister_vtable_reflection_type() in
2162 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2165 mono_domain_unlock (domain);
2166 mono_loader_unlock ();
2168 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2169 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2170 mono_raise_exception (mono_class_get_exception_for_failure (class));
2172 /* make sure the parent is initialized */
2173 /*FIXME shouldn't this fail the current type?*/
2175 mono_class_vtable_full (domain, class->parent, raise_on_error);
2181 * mono_class_proxy_vtable:
2182 * @domain: the application domain
2183 * @remove_class: the remote class
2185 * Creates a vtable for transparent proxies. It is basically
2186 * a copy of the real vtable of the class wrapped in @remote_class,
2187 * but all function pointers invoke the remoting functions, and
2188 * vtable->klass points to the transparent proxy class, and not to @class.
2191 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2194 MonoVTable *vt, *pvt;
2195 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2197 GSList *extra_interfaces = NULL;
2198 MonoClass *class = remote_class->proxy_class;
2199 gpointer *interface_offsets;
2203 #ifdef COMPRESSED_INTERFACE_BITMAP
2207 vt = mono_class_vtable (domain, class);
2208 g_assert (vt); /*FIXME property handle failure*/
2209 max_interface_id = vt->max_interface_id;
2211 /* Calculate vtable space for extra interfaces */
2212 for (j = 0; j < remote_class->interface_count; j++) {
2213 MonoClass* iclass = remote_class->interfaces[j];
2217 /*FIXME test for interfaces with variant generic arguments*/
2218 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2219 continue; /* interface implemented by the class */
2220 if (g_slist_find (extra_interfaces, iclass))
2223 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2225 method_count = mono_class_num_methods (iclass);
2227 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2228 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2230 for (i = 0; i < ifaces->len; ++i) {
2231 MonoClass *ic = g_ptr_array_index (ifaces, i);
2232 /*FIXME test for interfaces with variant generic arguments*/
2233 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2234 continue; /* interface implemented by the class */
2235 if (g_slist_find (extra_interfaces, ic))
2237 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2238 method_count += mono_class_num_methods (ic);
2240 g_ptr_array_free (ifaces, TRUE);
2243 extra_interface_vtsize += method_count * sizeof (gpointer);
2244 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2248 mono_stats.imt_number_of_tables++;
2249 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2250 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2251 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2253 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2254 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2257 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2259 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2261 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2263 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2264 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2266 pvt->klass = mono_defaults.transparent_proxy_class;
2267 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2268 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2270 /* initialize vtable */
2271 mono_class_setup_vtable (class);
2272 for (i = 0; i < class->vtable_size; ++i) {
2275 if ((cm = class->vtable [i]))
2276 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2278 pvt->vtable [i] = NULL;
2281 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2282 /* create trampolines for abstract methods */
2283 for (k = class; k; k = k->parent) {
2285 gpointer iter = NULL;
2286 while ((m = mono_class_get_methods (k, &iter)))
2287 if (!pvt->vtable [m->slot])
2288 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2292 pvt->max_interface_id = max_interface_id;
2293 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2294 #ifdef COMPRESSED_INTERFACE_BITMAP
2295 bitmap = g_malloc0 (bsize);
2297 bitmap = mono_domain_alloc0 (domain, bsize);
2300 if (! ARCH_USE_IMT) {
2301 /* initialize interface offsets */
2302 for (i = 0; i < class->interface_offsets_count; ++i) {
2303 int interface_id = class->interfaces_packed [i]->interface_id;
2304 int slot = class->interface_offsets_packed [i];
2305 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2308 for (i = 0; i < class->interface_offsets_count; ++i) {
2309 int interface_id = class->interfaces_packed [i]->interface_id;
2310 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2313 if (extra_interfaces) {
2314 int slot = class->vtable_size;
2320 /* Create trampolines for the methods of the interfaces */
2321 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2322 interf = list_item->data;
2324 if (! ARCH_USE_IMT) {
2325 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2327 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2331 while ((cm = mono_class_get_methods (interf, &iter)))
2332 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2334 slot += mono_class_num_methods (interf);
2336 if (! ARCH_USE_IMT) {
2337 g_slist_free (extra_interfaces);
2342 /* Now that the vtable is full, we can actually fill up the IMT */
2343 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2344 if (extra_interfaces) {
2345 g_slist_free (extra_interfaces);
2349 #ifdef COMPRESSED_INTERFACE_BITMAP
2350 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2351 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2352 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2355 pvt->interface_bitmap = bitmap;
2361 * mono_class_field_is_special_static:
2363 * Returns whether @field is a thread/context static field.
2366 mono_class_field_is_special_static (MonoClassField *field)
2368 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2370 if (mono_field_is_deleted (field))
2372 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2373 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2380 * mono_class_field_get_special_static_type:
2381 * @field: The MonoClassField describing the field.
2383 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2384 * SPECIAL_STATIC_NONE otherwise.
2387 mono_class_field_get_special_static_type (MonoClassField *field)
2389 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2390 return SPECIAL_STATIC_NONE;
2391 if (mono_field_is_deleted (field))
2392 return SPECIAL_STATIC_NONE;
2393 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2394 return field_is_special_static (field->parent, field);
2395 return SPECIAL_STATIC_NONE;
2399 * mono_class_has_special_static_fields:
2401 * Returns whenever @klass has any thread/context static fields.
2404 mono_class_has_special_static_fields (MonoClass *klass)
2406 MonoClassField *field;
2410 while ((field = mono_class_get_fields (klass, &iter))) {
2411 g_assert (field->parent == klass);
2412 if (mono_class_field_is_special_static (field))
2420 * create_remote_class_key:
2421 * Creates an array of pointers that can be used as a hash key for a remote class.
2422 * The first element of the array is the number of pointers.
2425 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2430 if (remote_class == NULL) {
2431 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2432 key = g_malloc (sizeof(gpointer) * 3);
2433 key [0] = GINT_TO_POINTER (2);
2434 key [1] = mono_defaults.marshalbyrefobject_class;
2435 key [2] = extra_class;
2437 key = g_malloc (sizeof(gpointer) * 2);
2438 key [0] = GINT_TO_POINTER (1);
2439 key [1] = extra_class;
2442 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2443 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2444 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2445 key [1] = remote_class->proxy_class;
2447 // Keep the list of interfaces sorted
2448 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2449 if (extra_class && remote_class->interfaces [i] > extra_class) {
2450 key [j++] = extra_class;
2453 key [j] = remote_class->interfaces [i];
2456 key [j] = extra_class;
2458 // Replace the old class. The interface list is the same
2459 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2460 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2461 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2462 for (i = 0; i < remote_class->interface_count; i++)
2463 key [2 + i] = remote_class->interfaces [i];
2471 * copy_remote_class_key:
2473 * Make a copy of KEY in the domain and return the copy.
2476 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2478 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2479 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2481 memcpy (mp_key, key, key_size);
2487 * mono_remote_class:
2488 * @domain: the application domain
2489 * @class_name: name of the remote class
2491 * Creates and initializes a MonoRemoteClass object for a remote type.
2493 * Can raise an exception on failure.
2496 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2499 MonoRemoteClass *rc;
2500 gpointer* key, *mp_key;
2503 key = create_remote_class_key (NULL, proxy_class);
2505 mono_domain_lock (domain);
2506 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2510 mono_domain_unlock (domain);
2514 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2515 if (!mono_error_ok (&error)) {
2517 mono_domain_unlock (domain);
2518 mono_error_raise_exception (&error);
2521 mp_key = copy_remote_class_key (domain, key);
2525 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2526 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2527 rc->interface_count = 1;
2528 rc->interfaces [0] = proxy_class;
2529 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2531 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2532 rc->interface_count = 0;
2533 rc->proxy_class = proxy_class;
2536 rc->default_vtable = NULL;
2537 rc->xdomain_vtable = NULL;
2538 rc->proxy_class_name = name;
2539 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2541 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2543 mono_domain_unlock (domain);
2548 * clone_remote_class:
2549 * Creates a copy of the remote_class, adding the provided class or interface
2551 static MonoRemoteClass*
2552 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2554 MonoRemoteClass *rc;
2555 gpointer* key, *mp_key;
2557 key = create_remote_class_key (remote_class, extra_class);
2558 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2564 mp_key = copy_remote_class_key (domain, key);
2568 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2570 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2571 rc->proxy_class = remote_class->proxy_class;
2572 rc->interface_count = remote_class->interface_count + 1;
2574 // Keep the list of interfaces sorted, since the hash key of
2575 // the remote class depends on this
2576 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2577 if (remote_class->interfaces [i] > extra_class && i == j)
2578 rc->interfaces [j++] = extra_class;
2579 rc->interfaces [j] = remote_class->interfaces [i];
2582 rc->interfaces [j] = extra_class;
2584 // Replace the old class. The interface array is the same
2585 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2586 rc->proxy_class = extra_class;
2587 rc->interface_count = remote_class->interface_count;
2588 if (rc->interface_count > 0)
2589 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2592 rc->default_vtable = NULL;
2593 rc->xdomain_vtable = NULL;
2594 rc->proxy_class_name = remote_class->proxy_class_name;
2596 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2602 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2604 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2605 mono_domain_lock (domain);
2606 if (rp->target_domain_id != -1) {
2607 if (remote_class->xdomain_vtable == NULL)
2608 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2609 mono_domain_unlock (domain);
2610 mono_loader_unlock ();
2611 return remote_class->xdomain_vtable;
2613 if (remote_class->default_vtable == NULL) {
2616 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2617 klass = mono_class_from_mono_type (type);
2618 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2619 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2621 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2624 mono_domain_unlock (domain);
2625 mono_loader_unlock ();
2626 return remote_class->default_vtable;
2630 * mono_upgrade_remote_class:
2631 * @domain: the application domain
2632 * @tproxy: the proxy whose remote class has to be upgraded.
2633 * @klass: class to which the remote class can be casted.
2635 * Updates the vtable of the remote class by adding the necessary method slots
2636 * and interface offsets so it can be safely casted to klass. klass can be a
2637 * class or an interface.
2640 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2642 MonoTransparentProxy *tproxy;
2643 MonoRemoteClass *remote_class;
2644 gboolean redo_vtable;
2646 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2647 mono_domain_lock (domain);
2649 tproxy = (MonoTransparentProxy*) proxy_object;
2650 remote_class = tproxy->remote_class;
2652 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2655 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2656 if (remote_class->interfaces [i] == klass)
2657 redo_vtable = FALSE;
2660 redo_vtable = (remote_class->proxy_class != klass);
2664 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2665 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2668 mono_domain_unlock (domain);
2669 mono_loader_unlock ();
2674 * mono_object_get_virtual_method:
2675 * @obj: object to operate on.
2678 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2679 * the instance of a callvirt of method.
2682 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2685 MonoMethod **vtable;
2687 MonoMethod *res = NULL;
2689 klass = mono_object_class (obj);
2690 if (klass == mono_defaults.transparent_proxy_class) {
2691 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2697 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2700 mono_class_setup_vtable (klass);
2701 vtable = klass->vtable;
2703 if (method->slot == -1) {
2704 /* method->slot might not be set for instances of generic methods */
2705 if (method->is_inflated) {
2706 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2707 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2710 g_assert_not_reached ();
2714 /* check method->slot is a valid index: perform isinstance? */
2715 if (method->slot != -1) {
2716 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2718 gboolean variance_used = FALSE;
2719 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2720 g_assert (iface_offset > 0);
2721 res = vtable [iface_offset + method->slot];
2724 res = vtable [method->slot];
2729 /* It may be an interface, abstract class method or generic method */
2730 if (!res || mono_method_signature (res)->generic_param_count)
2733 /* generic methods demand invoke_with_check */
2734 if (mono_method_signature (res)->generic_param_count)
2735 res = mono_marshal_get_remoting_invoke_with_check (res);
2738 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2739 res = mono_cominterop_get_invoke (res);
2742 res = mono_marshal_get_remoting_invoke (res);
2745 if (method->is_inflated) {
2746 /* Have to inflate the result */
2747 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2757 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2759 g_error ("runtime invoke called on uninitialized runtime");
2763 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2766 * mono_runtime_invoke:
2767 * @method: method to invoke
2768 * @obJ: object instance
2769 * @params: arguments to the method
2770 * @exc: exception information.
2772 * Invokes the method represented by @method on the object @obj.
2774 * obj is the 'this' pointer, it should be NULL for static
2775 * methods, a MonoObject* for object instances and a pointer to
2776 * the value type for value types.
2778 * The params array contains the arguments to the method with the
2779 * same convention: MonoObject* pointers for object instances and
2780 * pointers to the value type otherwise.
2782 * From unmanaged code you'll usually use the
2783 * mono_runtime_invoke() variant.
2785 * Note that this function doesn't handle virtual methods for
2786 * you, it will exec the exact method you pass: we still need to
2787 * expose a function to lookup the derived class implementation
2788 * of a virtual method (there are examples of this in the code,
2791 * You can pass NULL as the exc argument if you don't want to
2792 * catch exceptions, otherwise, *exc will be set to the exception
2793 * thrown, if any. if an exception is thrown, you can't use the
2794 * MonoObject* result from the function.
2796 * If the method returns a value type, it is boxed in an object
2800 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2804 if (mono_runtime_get_no_exec ())
2805 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2807 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2808 mono_profiler_method_start_invoke (method);
2810 result = default_mono_runtime_invoke (method, obj, params, exc);
2812 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2813 mono_profiler_method_end_invoke (method);
2819 * mono_method_get_unmanaged_thunk:
2820 * @method: method to generate a thunk for.
2822 * Returns an unmanaged->managed thunk that can be used to call
2823 * a managed method directly from C.
2825 * The thunk's C signature closely matches the managed signature:
2827 * C#: public bool Equals (object obj);
2828 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2829 * MonoObject*, MonoException**);
2831 * The 1st ("this") parameter must not be used with static methods:
2833 * C#: public static bool ReferenceEquals (object a, object b);
2834 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2837 * The last argument must be a non-null pointer of a MonoException* pointer.
2838 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2839 * exception has been thrown in managed code. Otherwise it will point
2840 * to the MonoException* caught by the thunk. In this case, the result of
2841 * the thunk is undefined:
2843 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2844 * MonoException *ex = NULL;
2845 * Equals func = mono_method_get_unmanaged_thunk (method);
2846 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2848 * // handle exception
2851 * The calling convention of the thunk matches the platform's default
2852 * convention. This means that under Windows, C declarations must
2853 * contain the __stdcall attribute:
2855 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2856 * MonoObject*, MonoException**);
2860 * Value type arguments and return values are treated as they were objects:
2862 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2863 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2865 * Arguments must be properly boxed upon trunk's invocation, while return
2866 * values must be unboxed.
2869 mono_method_get_unmanaged_thunk (MonoMethod *method)
2871 method = mono_marshal_get_thunk_invoke_wrapper (method);
2872 return mono_compile_method (method);
2876 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2880 /* object fields cannot be byref, so we don't need a
2882 gpointer *p = (gpointer*)dest;
2889 case MONO_TYPE_BOOLEAN:
2891 case MONO_TYPE_U1: {
2892 guint8 *p = (guint8*)dest;
2893 *p = value ? *(guint8*)value : 0;
2898 case MONO_TYPE_CHAR: {
2899 guint16 *p = (guint16*)dest;
2900 *p = value ? *(guint16*)value : 0;
2903 #if SIZEOF_VOID_P == 4
2908 case MONO_TYPE_U4: {
2909 gint32 *p = (gint32*)dest;
2910 *p = value ? *(gint32*)value : 0;
2913 #if SIZEOF_VOID_P == 8
2918 case MONO_TYPE_U8: {
2919 gint64 *p = (gint64*)dest;
2920 *p = value ? *(gint64*)value : 0;
2923 case MONO_TYPE_R4: {
2924 float *p = (float*)dest;
2925 *p = value ? *(float*)value : 0;
2928 case MONO_TYPE_R8: {
2929 double *p = (double*)dest;
2930 *p = value ? *(double*)value : 0;
2933 case MONO_TYPE_STRING:
2934 case MONO_TYPE_SZARRAY:
2935 case MONO_TYPE_CLASS:
2936 case MONO_TYPE_OBJECT:
2937 case MONO_TYPE_ARRAY:
2938 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2940 case MONO_TYPE_FNPTR:
2941 case MONO_TYPE_PTR: {
2942 gpointer *p = (gpointer*)dest;
2943 *p = deref_pointer? *(gpointer*)value: value;
2946 case MONO_TYPE_VALUETYPE:
2947 /* note that 't' and 'type->type' can be different */
2948 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2949 t = mono_class_enum_basetype (type->data.klass)->type;
2952 MonoClass *class = mono_class_from_mono_type (type);
2953 int size = mono_class_value_size (class, NULL);
2955 mono_gc_bzero (dest, size);
2957 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2960 case MONO_TYPE_GENERICINST:
2961 t = type->data.generic_class->container_class->byval_arg.type;
2964 g_error ("got type %x", type->type);
2969 * mono_field_set_value:
2970 * @obj: Instance object
2971 * @field: MonoClassField describing the field to set
2972 * @value: The value to be set
2974 * Sets the value of the field described by @field in the object instance @obj
2975 * to the value passed in @value. This method should only be used for instance
2976 * fields. For static fields, use mono_field_static_set_value.
2978 * The value must be on the native format of the field type.
2981 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2985 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2987 dest = (char*)obj + field->offset;
2988 set_value (field->type, dest, value, FALSE);
2992 * mono_field_static_set_value:
2993 * @field: MonoClassField describing the field to set
2994 * @value: The value to be set
2996 * Sets the value of the static field described by @field
2997 * to the value passed in @value.
2999 * The value must be on the native format of the field type.
3002 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3006 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3007 /* you cant set a constant! */
3008 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3010 if (field->offset == -1) {
3011 /* Special static */
3014 mono_domain_lock (vt->domain);
3015 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3016 mono_domain_unlock (vt->domain);
3017 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3019 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3021 set_value (field->type, dest, value, FALSE);
3025 * mono_vtable_get_static_field_data:
3027 * Internal use function: return a pointer to the memory holding the static fields
3028 * for a class or NULL if there are no static fields.
3029 * This is exported only for use by the debugger.
3032 mono_vtable_get_static_field_data (MonoVTable *vt)
3034 if (!vt->has_static_fields)
3036 return vt->vtable [vt->klass->vtable_size];
3040 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3044 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3045 if (field->offset == -1) {
3046 /* Special static */
3049 mono_domain_lock (vt->domain);
3050 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3051 mono_domain_unlock (vt->domain);
3052 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3054 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3057 src = (guint8*)obj + field->offset;
3064 * mono_field_get_value:
3065 * @obj: Object instance
3066 * @field: MonoClassField describing the field to fetch information from
3067 * @value: pointer to the location where the value will be stored
3069 * Use this routine to get the value of the field @field in the object
3072 * The pointer provided by value must be of the field type, for reference
3073 * types this is a MonoObject*, for value types its the actual pointer to
3078 * mono_field_get_value (obj, int_field, &i);
3081 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3087 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3089 src = (char*)obj + field->offset;
3090 set_value (field->type, value, src, TRUE);
3094 * mono_field_get_value_object:
3095 * @domain: domain where the object will be created (if boxing)
3096 * @field: MonoClassField describing the field to fetch information from
3097 * @obj: The object instance for the field.
3099 * Returns: a new MonoObject with the value from the given field. If the
3100 * field represents a value type, the value is boxed.
3104 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3108 MonoVTable *vtable = NULL;
3110 gboolean is_static = FALSE;
3111 gboolean is_ref = FALSE;
3112 gboolean is_literal = FALSE;
3113 gboolean is_ptr = FALSE;
3115 MonoType *type = mono_field_get_type_checked (field, &error);
3117 if (!mono_error_ok (&error))
3118 mono_error_raise_exception (&error);
3120 switch (type->type) {
3121 case MONO_TYPE_STRING:
3122 case MONO_TYPE_OBJECT:
3123 case MONO_TYPE_CLASS:
3124 case MONO_TYPE_ARRAY:
3125 case MONO_TYPE_SZARRAY:
3130 case MONO_TYPE_BOOLEAN:
3133 case MONO_TYPE_CHAR:
3142 case MONO_TYPE_VALUETYPE:
3143 is_ref = type->byref;
3145 case MONO_TYPE_GENERICINST:
3146 is_ref = !mono_type_generic_inst_is_valuetype (type);
3152 g_error ("type 0x%x not handled in "
3153 "mono_field_get_value_object", type->type);
3157 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3160 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3164 vtable = mono_class_vtable (domain, field->parent);
3166 char *name = mono_type_get_full_name (field->parent);
3167 /*FIXME extend this to use the MonoError api*/
3168 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3172 if (!vtable->initialized)
3173 mono_runtime_class_init (vtable);
3181 get_default_field_value (domain, field, &o);
3182 } else if (is_static) {
3183 mono_field_static_get_value (vtable, field, &o);
3185 mono_field_get_value (obj, field, &o);
3191 static MonoMethod *m;
3197 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3198 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3204 get_default_field_value (domain, field, v);
3205 } else if (is_static) {
3206 mono_field_static_get_value (vtable, field, v);
3208 mono_field_get_value (obj, field, v);
3211 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3213 args [1] = mono_type_get_object (mono_domain_get (), type);
3215 return mono_runtime_invoke (m, NULL, args, NULL);
3218 /* boxed value type */
3219 klass = mono_class_from_mono_type (type);
3221 if (mono_class_is_nullable (klass))
3222 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3224 o = mono_object_new (domain, klass);
3225 v = ((gchar *) o) + sizeof (MonoObject);
3228 get_default_field_value (domain, field, v);
3229 } else if (is_static) {
3230 mono_field_static_get_value (vtable, field, v);
3232 mono_field_get_value (obj, field, v);
3239 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3242 const char *p = blob;
3243 mono_metadata_decode_blob_size (p, &p);
3246 case MONO_TYPE_BOOLEAN:
3249 *(guint8 *) value = *p;
3251 case MONO_TYPE_CHAR:
3254 *(guint16*) value = read16 (p);
3258 *(guint32*) value = read32 (p);
3262 *(guint64*) value = read64 (p);
3265 readr4 (p, (float*) value);
3268 readr8 (p, (double*) value);
3270 case MONO_TYPE_STRING:
3271 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3273 case MONO_TYPE_CLASS:
3274 *(gpointer*) value = NULL;
3278 g_warning ("type 0x%02x should not be in constant table", type);
3284 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3286 MonoTypeEnum def_type;
3289 data = mono_class_get_field_default_value (field, &def_type);
3290 mono_get_constant_value_from_blob (domain, def_type, data, value);
3294 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3298 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3300 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3301 get_default_field_value (vt->domain, field, value);
3305 if (field->offset == -1) {
3306 /* Special static */
3307 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3308 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3310 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3312 set_value (field->type, value, src, TRUE);
3316 * mono_field_static_get_value:
3317 * @vt: vtable to the object
3318 * @field: MonoClassField describing the field to fetch information from
3319 * @value: where the value is returned
3321 * Use this routine to get the value of the static field @field value.
3323 * The pointer provided by value must be of the field type, for reference
3324 * types this is a MonoObject*, for value types its the actual pointer to
3329 * mono_field_static_get_value (vt, int_field, &i);
3332 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3334 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3338 * mono_property_set_value:
3339 * @prop: MonoProperty to set
3340 * @obj: instance object on which to act
3341 * @params: parameters to pass to the propery
3342 * @exc: optional exception
3344 * Invokes the property's set method with the given arguments on the
3345 * object instance obj (or NULL for static properties).
3347 * You can pass NULL as the exc argument if you don't want to
3348 * catch exceptions, otherwise, *exc will be set to the exception
3349 * thrown, if any. if an exception is thrown, you can't use the
3350 * MonoObject* result from the function.
3353 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3355 default_mono_runtime_invoke (prop->set, obj, params, exc);
3359 * mono_property_get_value:
3360 * @prop: MonoProperty to fetch
3361 * @obj: instance object on which to act
3362 * @params: parameters to pass to the propery
3363 * @exc: optional exception
3365 * Invokes the property's get method with the given arguments on the
3366 * object instance obj (or NULL for static properties).
3368 * You can pass NULL as the exc argument if you don't want to
3369 * catch exceptions, otherwise, *exc will be set to the exception
3370 * thrown, if any. if an exception is thrown, you can't use the
3371 * MonoObject* result from the function.
3373 * Returns: the value from invoking the get method on the property.
3376 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3378 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3382 * mono_nullable_init:
3383 * @buf: The nullable structure to initialize.
3384 * @value: the value to initialize from
3385 * @klass: the type for the object
3387 * Initialize the nullable structure pointed to by @buf from @value which
3388 * should be a boxed value type. The size of @buf should be able to hold
3389 * as much data as the @klass->instance_size (which is the number of bytes
3390 * that will be copies).
3392 * Since Nullables have variable structure, we can not define a C
3393 * structure for them.
3396 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3398 MonoClass *param_class = klass->cast_class;
3400 mono_class_setup_fields_locking (klass);
3401 g_assert (klass->fields_inited);
3403 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3404 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3406 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3408 if (param_class->has_references)
3409 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3411 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3413 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3418 * mono_nullable_box:
3419 * @buf: The buffer representing the data to be boxed
3420 * @klass: the type to box it as.
3422 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3426 mono_nullable_box (guint8 *buf, MonoClass *klass)
3428 MonoClass *param_class = klass->cast_class;
3430 mono_class_setup_fields_locking (klass);
3431 g_assert (klass->fields_inited);
3433 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3434 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3436 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3437 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3438 if (param_class->has_references)
3439 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3441 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3449 * mono_get_delegate_invoke:
3450 * @klass: The delegate class
3452 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3455 mono_get_delegate_invoke (MonoClass *klass)
3459 /* This is called at runtime, so avoid the slower search in metadata */
3460 mono_class_setup_methods (klass);
3461 if (klass->exception_type)
3463 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3468 * mono_runtime_delegate_invoke:
3469 * @delegate: pointer to a delegate object.
3470 * @params: parameters for the delegate.
3471 * @exc: Pointer to the exception result.
3473 * Invokes the delegate method @delegate with the parameters provided.
3475 * You can pass NULL as the exc argument if you don't want to
3476 * catch exceptions, otherwise, *exc will be set to the exception
3477 * thrown, if any. if an exception is thrown, you can't use the
3478 * MonoObject* result from the function.
3481 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3484 MonoClass *klass = delegate->vtable->klass;
3486 im = mono_get_delegate_invoke (klass);
3488 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3490 return mono_runtime_invoke (im, delegate, params, exc);
3493 static char **main_args = NULL;
3494 static int num_main_args;
3497 * mono_runtime_get_main_args:
3499 * Returns: a MonoArray with the arguments passed to the main program
3502 mono_runtime_get_main_args (void)
3506 MonoDomain *domain = mono_domain_get ();
3511 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3513 for (i = 0; i < num_main_args; ++i)
3514 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3520 free_main_args (void)
3524 for (i = 0; i < num_main_args; ++i)
3525 g_free (main_args [i]);
3530 * mono_runtime_run_main:
3531 * @method: the method to start the application with (usually Main)
3532 * @argc: number of arguments from the command line
3533 * @argv: array of strings from the command line
3534 * @exc: excetption results
3536 * Execute a standard Main() method (argc/argv contains the
3537 * executable name). This method also sets the command line argument value
3538 * needed by System.Environment.
3543 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3547 MonoArray *args = NULL;
3548 MonoDomain *domain = mono_domain_get ();
3549 gchar *utf8_fullpath;
3550 MonoMethodSignature *sig;
3552 g_assert (method != NULL);
3554 mono_thread_set_main (mono_thread_current ());
3556 main_args = g_new0 (char*, argc);
3557 num_main_args = argc;
3559 if (!g_path_is_absolute (argv [0])) {
3560 gchar *basename = g_path_get_basename (argv [0]);
3561 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3565 utf8_fullpath = mono_utf8_from_external (fullpath);
3566 if(utf8_fullpath == NULL) {
3567 /* Printing the arg text will cause glib to
3568 * whinge about "Invalid UTF-8", but at least
3569 * its relevant, and shows the problem text
3572 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3573 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3580 utf8_fullpath = mono_utf8_from_external (argv[0]);
3581 if(utf8_fullpath == NULL) {
3582 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3583 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3588 main_args [0] = utf8_fullpath;
3590 for (i = 1; i < argc; ++i) {
3593 utf8_arg=mono_utf8_from_external (argv[i]);
3594 if(utf8_arg==NULL) {
3595 /* Ditto the comment about Invalid UTF-8 here */
3596 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3597 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3601 main_args [i] = utf8_arg;
3606 sig = mono_method_signature (method);
3608 g_print ("Unable to load Main method.\n");
3612 if (sig->param_count) {
3613 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3614 for (i = 0; i < argc; ++i) {
3615 /* The encodings should all work, given that
3616 * we've checked all these args for the
3619 gchar *str = mono_utf8_from_external (argv [i]);
3620 MonoString *arg = mono_string_new (domain, str);
3621 mono_array_setref (args, i, arg);
3625 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3628 mono_assembly_set_main (method->klass->image->assembly);
3630 return mono_runtime_exec_main (method, args, exc);
3634 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3636 static MonoMethod *serialize_method;
3641 if (!serialize_method) {
3642 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3643 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3646 if (!serialize_method) {
3651 g_assert (!mono_object_class (obj)->marshalbyref);
3655 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3663 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3665 static MonoMethod *deserialize_method;
3670 if (!deserialize_method) {
3671 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3672 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3674 if (!deserialize_method) {
3681 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3689 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3691 static MonoMethod *get_proxy_method;
3693 MonoDomain *domain = mono_domain_get ();
3694 MonoRealProxy *real_proxy;
3695 MonoReflectionType *reflection_type;
3696 MonoTransparentProxy *transparent_proxy;
3698 if (!get_proxy_method)
3699 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3701 g_assert (obj->vtable->klass->marshalbyref);
3703 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3704 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3706 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3707 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3710 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3714 return (MonoObject*) transparent_proxy;
3718 * mono_object_xdomain_representation
3720 * @target_domain: a domain
3721 * @exc: pointer to a MonoObject*
3723 * Creates a representation of obj in the domain target_domain. This
3724 * is either a copy of obj arrived through via serialization and
3725 * deserialization or a proxy, depending on whether the object is
3726 * serializable or marshal by ref. obj must not be in target_domain.
3728 * If the object cannot be represented in target_domain, NULL is
3729 * returned and *exc is set to an appropriate exception.
3732 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3734 MonoObject *deserialized = NULL;
3735 gboolean failure = FALSE;
3739 if (mono_object_class (obj)->marshalbyref) {
3740 deserialized = make_transparent_proxy (obj, &failure, exc);
3742 MonoDomain *domain = mono_domain_get ();
3743 MonoObject *serialized;
3745 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3746 serialized = serialize_object (obj, &failure, exc);
3747 mono_domain_set_internal_with_options (target_domain, FALSE);
3749 deserialized = deserialize_object (serialized, &failure, exc);
3750 if (domain != target_domain)
3751 mono_domain_set_internal_with_options (domain, FALSE);
3754 return deserialized;
3757 /* Used in call_unhandled_exception_delegate */
3759 create_unhandled_exception_eventargs (MonoObject *exc)
3763 MonoMethod *method = NULL;
3764 MonoBoolean is_terminating = TRUE;
3767 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3770 mono_class_init (klass);
3772 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3773 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3777 args [1] = &is_terminating;
3779 obj = mono_object_new (mono_domain_get (), klass);
3780 mono_runtime_invoke (method, obj, args, NULL);
3785 /* Used in mono_unhandled_exception */
3787 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3788 MonoObject *e = NULL;
3790 MonoDomain *current_domain = mono_domain_get ();
3792 if (domain != current_domain)
3793 mono_domain_set_internal_with_options (domain, FALSE);
3795 g_assert (domain == mono_object_domain (domain->domain));
3797 if (mono_object_domain (exc) != domain) {
3798 MonoObject *serialization_exc;
3800 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3802 if (serialization_exc) {
3804 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3807 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3808 "System.Runtime.Serialization", "SerializationException",
3809 "Could not serialize unhandled exception.");
3813 g_assert (mono_object_domain (exc) == domain);
3815 pa [0] = domain->domain;
3816 pa [1] = create_unhandled_exception_eventargs (exc);
3817 mono_runtime_delegate_invoke (delegate, pa, &e);
3819 if (domain != current_domain)
3820 mono_domain_set_internal_with_options (current_domain, FALSE);
3824 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3825 if (!mono_error_ok (&error)) {
3826 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3827 mono_error_cleanup (&error);
3829 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3835 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3838 * mono_runtime_unhandled_exception_policy_set:
3839 * @policy: the new policy
3841 * This is a VM internal routine.
3843 * Sets the runtime policy for handling unhandled exceptions.
3846 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3847 runtime_unhandled_exception_policy = policy;
3851 * mono_runtime_unhandled_exception_policy_get:
3853 * This is a VM internal routine.
3855 * Gets the runtime policy for handling unhandled exceptions.
3857 MonoRuntimeUnhandledExceptionPolicy
3858 mono_runtime_unhandled_exception_policy_get (void) {
3859 return runtime_unhandled_exception_policy;
3863 * mono_unhandled_exception:
3864 * @exc: exception thrown
3866 * This is a VM internal routine.
3868 * We call this function when we detect an unhandled exception
3869 * in the default domain.
3871 * It invokes the * UnhandledException event in AppDomain or prints
3872 * a warning to the console
3875 mono_unhandled_exception (MonoObject *exc)
3877 MonoDomain *current_domain = mono_domain_get ();
3878 MonoDomain *root_domain = mono_get_root_domain ();
3879 MonoClassField *field;
3880 MonoObject *current_appdomain_delegate;
3881 MonoObject *root_appdomain_delegate;
3883 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3884 "UnhandledException");
3887 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3888 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3889 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3890 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3891 if (current_domain != root_domain) {
3892 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3894 current_appdomain_delegate = NULL;
3897 /* set exitcode only if we will abort the process */
3898 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3900 mono_environment_exitcode_set (1);
3901 mono_print_unhandled_exception (exc);
3903 if (root_appdomain_delegate) {
3904 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3906 if (current_appdomain_delegate) {
3907 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3914 * mono_runtime_exec_managed_code:
3915 * @domain: Application domain
3916 * @main_func: function to invoke from the execution thread
3917 * @main_args: parameter to the main_func
3919 * Launch a new thread to execute a function
3921 * main_func is called back from the thread with main_args as the
3922 * parameter. The callback function is expected to start Main()
3923 * eventually. This function then waits for all managed threads to
3925 * It is not necesseray anymore to execute managed code in a subthread,
3926 * so this function should not be used anymore by default: just
3927 * execute the code and then call mono_thread_manage ().
3930 mono_runtime_exec_managed_code (MonoDomain *domain,
3931 MonoMainThreadFunc main_func,
3934 mono_thread_create (domain, main_func, main_args);
3936 mono_thread_manage ();
3940 * Execute a standard Main() method (args doesn't contain the
3944 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3949 MonoCustomAttrInfo* cinfo;
3950 gboolean has_stathread_attribute;
3951 MonoInternalThread* thread = mono_thread_internal_current ();
3957 domain = mono_object_domain (args);
3958 if (!domain->entry_assembly) {
3960 MonoAssembly *assembly;
3962 assembly = method->klass->image->assembly;
3963 domain->entry_assembly = assembly;
3964 /* Domains created from another domain already have application_base and configuration_file set */
3965 if (domain->setup->application_base == NULL) {
3966 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3969 if (domain->setup->configuration_file == NULL) {
3970 str = g_strconcat (assembly->image->name, ".config", NULL);
3971 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3973 mono_set_private_bin_path_from_config (domain);
3977 cinfo = mono_custom_attrs_from_method (method);
3979 static MonoClass *stathread_attribute = NULL;
3980 if (!stathread_attribute)
3981 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3982 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3984 mono_custom_attrs_free (cinfo);
3986 has_stathread_attribute = FALSE;
3988 if (has_stathread_attribute) {
3989 thread->apartment_state = ThreadApartmentState_STA;
3991 thread->apartment_state = ThreadApartmentState_MTA;
3993 mono_thread_init_apartment_state ();
3995 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3997 /* FIXME: check signature of method */
3998 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4000 res = mono_runtime_invoke (method, NULL, pa, exc);
4002 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4006 mono_environment_exitcode_set (rval);
4008 mono_runtime_invoke (method, NULL, pa, exc);
4012 /* If the return type of Main is void, only
4013 * set the exitcode if an exception was thrown
4014 * (we don't want to blow away an
4015 * explicitly-set exit code)
4018 mono_environment_exitcode_set (rval);
4022 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4028 * mono_install_runtime_invoke:
4029 * @func: Function to install
4031 * This is a VM internal routine
4034 mono_install_runtime_invoke (MonoInvokeFunc func)
4036 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4041 * mono_runtime_invoke_array:
4042 * @method: method to invoke
4043 * @obJ: object instance
4044 * @params: arguments to the method
4045 * @exc: exception information.
4047 * Invokes the method represented by @method on the object @obj.
4049 * obj is the 'this' pointer, it should be NULL for static
4050 * methods, a MonoObject* for object instances and a pointer to
4051 * the value type for value types.
4053 * The params array contains the arguments to the method with the
4054 * same convention: MonoObject* pointers for object instances and
4055 * pointers to the value type otherwise. The _invoke_array
4056 * variant takes a C# object[] as the params argument (MonoArray
4057 * *params): in this case the value types are boxed inside the
4058 * respective reference representation.
4060 * From unmanaged code you'll usually use the
4061 * mono_runtime_invoke() variant.
4063 * Note that this function doesn't handle virtual methods for
4064 * you, it will exec the exact method you pass: we still need to
4065 * expose a function to lookup the derived class implementation
4066 * of a virtual method (there are examples of this in the code,
4069 * You can pass NULL as the exc argument if you don't want to
4070 * catch exceptions, otherwise, *exc will be set to the exception
4071 * thrown, if any. if an exception is thrown, you can't use the
4072 * MonoObject* result from the function.
4074 * If the method returns a value type, it is boxed in an object
4078 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4081 MonoMethodSignature *sig = mono_method_signature (method);
4082 gpointer *pa = NULL;
4085 gboolean has_byref_nullables = FALSE;
4087 if (NULL != params) {
4088 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4089 for (i = 0; i < mono_array_length (params); i++) {
4090 MonoType *t = sig->params [i];
4096 case MONO_TYPE_BOOLEAN:
4099 case MONO_TYPE_CHAR:
4108 case MONO_TYPE_VALUETYPE:
4109 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4110 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4111 pa [i] = mono_array_get (params, MonoObject*, i);
4113 has_byref_nullables = TRUE;
4115 /* MS seems to create the objects if a null is passed in */
4116 if (!mono_array_get (params, MonoObject*, i))
4117 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4121 * We can't pass the unboxed vtype byref to the callee, since
4122 * that would mean the callee would be able to modify boxed
4123 * primitive types. So we (and MS) make a copy of the boxed
4124 * object, pass that to the callee, and replace the original
4125 * boxed object in the arg array with the copy.
4127 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4128 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4129 mono_array_setref (params, i, copy);
4132 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4135 case MONO_TYPE_STRING:
4136 case MONO_TYPE_OBJECT:
4137 case MONO_TYPE_CLASS:
4138 case MONO_TYPE_ARRAY:
4139 case MONO_TYPE_SZARRAY:
4141 pa [i] = mono_array_addr (params, MonoObject*, i);
4142 // FIXME: I need to check this code path
4144 pa [i] = mono_array_get (params, MonoObject*, i);
4146 case MONO_TYPE_GENERICINST:
4148 t = &t->data.generic_class->container_class->this_arg;
4150 t = &t->data.generic_class->container_class->byval_arg;
4152 case MONO_TYPE_PTR: {
4155 /* The argument should be an IntPtr */
4156 arg = mono_array_get (params, MonoObject*, i);
4160 g_assert (arg->vtable->klass == mono_defaults.int_class);
4161 pa [i] = ((MonoIntPtr*)arg)->m_value;
4166 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4171 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4174 if (mono_class_is_nullable (method->klass)) {
4175 /* Need to create a boxed vtype instead */
4181 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4185 obj = mono_object_new (mono_domain_get (), method->klass);
4186 g_assert (obj); /*maybe we should raise a TLE instead?*/
4187 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4188 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4190 if (method->klass->valuetype)
4191 o = mono_object_unbox (obj);
4194 } else if (method->klass->valuetype) {
4195 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4198 mono_runtime_invoke (method, o, pa, exc);
4201 if (mono_class_is_nullable (method->klass)) {
4202 MonoObject *nullable;
4204 /* Convert the unboxed vtype into a Nullable structure */
4205 nullable = mono_object_new (mono_domain_get (), method->klass);
4207 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4208 obj = mono_object_unbox (nullable);
4211 /* obj must be already unboxed if needed */
4212 res = mono_runtime_invoke (method, obj, pa, exc);
4214 if (sig->ret->type == MONO_TYPE_PTR) {
4215 MonoClass *pointer_class;
4216 static MonoMethod *box_method;
4218 MonoObject *box_exc;
4221 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4222 * convert it to a Pointer object.
4224 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4226 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4228 g_assert (res->vtable->klass == mono_defaults.int_class);
4229 box_args [0] = ((MonoIntPtr*)res)->m_value;
4230 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4231 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4232 g_assert (!box_exc);
4235 if (has_byref_nullables) {
4237 * The runtime invoke wrapper already converted byref nullables back,
4238 * and stored them in pa, we just need to copy them back to the
4241 for (i = 0; i < mono_array_length (params); i++) {
4242 MonoType *t = sig->params [i];
4244 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4245 mono_array_setref (params, i, pa [i]);
4254 arith_overflow (void)
4256 mono_raise_exception (mono_get_exception_overflow ());
4260 * mono_object_allocate:
4261 * @size: number of bytes to allocate
4263 * This is a very simplistic routine until we have our GC-aware
4266 * Returns: an allocated object of size @size, or NULL on failure.
4268 static inline void *
4269 mono_object_allocate (size_t size, MonoVTable *vtable)
4272 mono_stats.new_object_count++;
4273 ALLOC_OBJECT (o, vtable, size);
4279 * mono_object_allocate_ptrfree:
4280 * @size: number of bytes to allocate
4282 * Note that the memory allocated is not zeroed.
4283 * Returns: an allocated object of size @size, or NULL on failure.
4285 static inline void *
4286 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4289 mono_stats.new_object_count++;
4290 ALLOC_PTRFREE (o, vtable, size);
4294 static inline void *
4295 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4298 ALLOC_TYPED (o, size, vtable);
4299 mono_stats.new_object_count++;
4306 * @klass: the class of the object that we want to create
4308 * Returns: a newly created object whose definition is
4309 * looked up using @klass. This will not invoke any constructors,
4310 * so the consumer of this routine has to invoke any constructors on
4311 * its own to initialize the object.
4313 * It returns NULL on failure.
4316 mono_object_new (MonoDomain *domain, MonoClass *klass)
4320 MONO_ARCH_SAVE_REGS;
4321 vtable = mono_class_vtable (domain, klass);
4324 return mono_object_new_specific (vtable);
4328 * mono_object_new_pinned:
4330 * Same as mono_object_new, but the returned object will be pinned.
4331 * For SGEN, these objects will only be freed at appdomain unload.
4334 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4338 MONO_ARCH_SAVE_REGS;
4339 vtable = mono_class_vtable (domain, klass);
4344 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4346 return mono_object_new_specific (vtable);
4351 * mono_object_new_specific:
4352 * @vtable: the vtable of the object that we want to create
4354 * Returns: A newly created object with class and domain specified
4358 mono_object_new_specific (MonoVTable *vtable)
4362 MONO_ARCH_SAVE_REGS;
4364 /* check for is_com_object for COM Interop */
4365 if (vtable->remote || vtable->klass->is_com_object)
4368 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4371 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4374 mono_class_init (klass);
4376 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4378 vtable->domain->create_proxy_for_type_method = im;
4381 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4383 o = mono_runtime_invoke (im, NULL, pa, NULL);
4384 if (o != NULL) return o;
4387 return mono_object_new_alloc_specific (vtable);
4391 mono_object_new_alloc_specific (MonoVTable *vtable)
4395 if (!vtable->klass->has_references) {
4396 o = mono_object_new_ptrfree (vtable);
4397 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4398 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4400 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4401 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4403 if (G_UNLIKELY (vtable->klass->has_finalize))
4404 mono_object_register_finalizer (o);
4406 if (G_UNLIKELY (profile_allocs))
4407 mono_profiler_allocation (o, vtable->klass);
4412 mono_object_new_fast (MonoVTable *vtable)
4415 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4420 mono_object_new_ptrfree (MonoVTable *vtable)
4423 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4424 #if NEED_TO_ZERO_PTRFREE
4425 /* an inline memset is much faster for the common vcase of small objects
4426 * note we assume the allocated size is a multiple of sizeof (void*).
4428 if (vtable->klass->instance_size < 128) {
4430 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4431 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4437 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4444 mono_object_new_ptrfree_box (MonoVTable *vtable)
4447 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4448 /* the object will be boxed right away, no need to memzero it */
4453 * mono_class_get_allocation_ftn:
4455 * @for_box: the object will be used for boxing
4456 * @pass_size_in_words:
4458 * Return the allocation function appropriate for the given class.
4462 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4464 *pass_size_in_words = FALSE;
4466 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4467 profile_allocs = FALSE;
4469 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4470 return mono_object_new_specific;
4472 if (!vtable->klass->has_references) {
4473 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4475 return mono_object_new_ptrfree_box;
4476 return mono_object_new_ptrfree;
4479 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4481 return mono_object_new_fast;
4484 * FIXME: This is actually slower than mono_object_new_fast, because
4485 * of the overhead of parameter passing.
4488 *pass_size_in_words = TRUE;
4489 #ifdef GC_REDIRECT_TO_LOCAL
4490 return GC_local_gcj_fast_malloc;
4492 return GC_gcj_fast_malloc;
4497 return mono_object_new_specific;
4501 * mono_object_new_from_token:
4502 * @image: Context where the type_token is hosted
4503 * @token: a token of the type that we want to create
4505 * Returns: A newly created object whose definition is
4506 * looked up using @token in the @image image
4509 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4513 class = mono_class_get (image, token);
4515 return mono_object_new (domain, class);
4520 * mono_object_clone:
4521 * @obj: the object to clone
4523 * Returns: A newly created object who is a shallow copy of @obj
4526 mono_object_clone (MonoObject *obj)
4529 int size = obj->vtable->klass->instance_size;
4531 if (obj->vtable->klass->rank)
4532 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4534 o = mono_object_allocate (size, obj->vtable);
4536 if (obj->vtable->klass->has_references) {
4537 mono_gc_wbarrier_object_copy (o, obj);
4539 int size = obj->vtable->klass->instance_size;
4540 /* do not copy the sync state */
4541 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4543 if (G_UNLIKELY (profile_allocs))
4544 mono_profiler_allocation (o, obj->vtable->klass);
4546 if (obj->vtable->klass->has_finalize)
4547 mono_object_register_finalizer (o);
4552 * mono_array_full_copy:
4553 * @src: source array to copy
4554 * @dest: destination array
4556 * Copies the content of one array to another with exactly the same type and size.
4559 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4562 MonoClass *klass = src->obj.vtable->klass;
4564 MONO_ARCH_SAVE_REGS;
4566 g_assert (klass == dest->obj.vtable->klass);
4568 size = mono_array_length (src);
4569 g_assert (size == mono_array_length (dest));
4570 size *= mono_array_element_size (klass);
4572 if (klass->element_class->valuetype) {
4573 if (klass->element_class->has_references)
4574 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4576 mono_gc_memmove (&dest->vector, &src->vector, size);
4578 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4581 mono_gc_memmove (&dest->vector, &src->vector, size);
4586 * mono_array_clone_in_domain:
4587 * @domain: the domain in which the array will be cloned into
4588 * @array: the array to clone
4590 * This routine returns a copy of the array that is hosted on the
4591 * specified MonoDomain.
4594 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4599 MonoClass *klass = array->obj.vtable->klass;
4601 MONO_ARCH_SAVE_REGS;
4603 if (array->bounds == NULL) {
4604 size = mono_array_length (array);
4605 o = mono_array_new_full (domain, klass, &size, NULL);
4607 size *= mono_array_element_size (klass);
4609 if (klass->element_class->valuetype) {
4610 if (klass->element_class->has_references)
4611 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4613 mono_gc_memmove (&o->vector, &array->vector, size);
4615 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4618 mono_gc_memmove (&o->vector, &array->vector, size);
4623 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4624 size = mono_array_element_size (klass);
4625 for (i = 0; i < klass->rank; ++i) {
4626 sizes [i] = array->bounds [i].length;
4627 size *= array->bounds [i].length;
4628 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4630 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4632 if (klass->element_class->valuetype) {
4633 if (klass->element_class->has_references)
4634 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4636 mono_gc_memmove (&o->vector, &array->vector, size);
4638 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4641 mono_gc_memmove (&o->vector, &array->vector, size);
4649 * @array: the array to clone
4651 * Returns: A newly created array who is a shallow copy of @array
4654 mono_array_clone (MonoArray *array)
4656 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4659 /* helper macros to check for overflow when calculating the size of arrays */
4660 #ifdef MONO_BIG_ARRAYS
4661 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4662 #define MYGUINT_MAX MYGUINT64_MAX
4663 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4664 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4665 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4666 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4667 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4669 #define MYGUINT32_MAX 4294967295U
4670 #define MYGUINT_MAX MYGUINT32_MAX
4671 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4672 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4673 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4674 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4675 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4679 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4683 byte_len = mono_array_element_size (class);
4684 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4687 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4689 byte_len += sizeof (MonoArray);
4697 * mono_array_new_full:
4698 * @domain: domain where the object is created
4699 * @array_class: array class
4700 * @lengths: lengths for each dimension in the array
4701 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4703 * This routine creates a new array objects with the given dimensions,
4704 * lower bounds and type.
4707 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4709 uintptr_t byte_len, len, bounds_size;
4712 MonoArrayBounds *bounds;
4716 if (!array_class->inited)
4717 mono_class_init (array_class);
4721 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4722 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4724 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4728 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4730 for (i = 0; i < array_class->rank; ++i) {
4731 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4733 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4734 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4739 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4740 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4744 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4745 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4746 byte_len = (byte_len + 3) & ~3;
4747 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4748 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4749 byte_len += bounds_size;
4752 * Following three lines almost taken from mono_object_new ():
4753 * they need to be kept in sync.
4755 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4756 #ifndef HAVE_SGEN_GC
4757 if (!array_class->has_references) {
4758 o = mono_object_allocate_ptrfree (byte_len, vtable);
4759 #if NEED_TO_ZERO_PTRFREE
4760 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4762 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4763 o = mono_object_allocate_spec (byte_len, vtable);
4765 o = mono_object_allocate (byte_len, vtable);
4768 array = (MonoArray*)o;
4769 array->max_length = len;
4772 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4773 array->bounds = bounds;
4777 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4779 o = mono_gc_alloc_vector (vtable, byte_len, len);
4780 array = (MonoArray*)o;
4781 mono_stats.new_object_count++;
4783 bounds = array->bounds;
4787 for (i = 0; i < array_class->rank; ++i) {
4788 bounds [i].length = lengths [i];
4790 bounds [i].lower_bound = lower_bounds [i];
4794 if (G_UNLIKELY (profile_allocs))
4795 mono_profiler_allocation (o, array_class);
4802 * @domain: domain where the object is created
4803 * @eclass: element class
4804 * @n: number of array elements
4806 * This routine creates a new szarray with @n elements of type @eclass.
4809 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4813 MONO_ARCH_SAVE_REGS;
4815 ac = mono_array_class_get (eclass, 1);
4818 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4822 * mono_array_new_specific:
4823 * @vtable: a vtable in the appropriate domain for an initialized class
4824 * @n: number of array elements
4826 * This routine is a fast alternative to mono_array_new() for code which
4827 * can be sure about the domain it operates in.
4830 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4836 MONO_ARCH_SAVE_REGS;
4838 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4843 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4844 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4847 #ifndef HAVE_SGEN_GC
4848 if (!vtable->klass->has_references) {
4849 o = mono_object_allocate_ptrfree (byte_len, vtable);
4850 #if NEED_TO_ZERO_PTRFREE
4851 ((MonoArray*)o)->bounds = NULL;
4852 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4854 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4855 o = mono_object_allocate_spec (byte_len, vtable);
4857 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4858 o = mono_object_allocate (byte_len, vtable);
4861 ao = (MonoArray *)o;
4864 o = mono_gc_alloc_vector (vtable, byte_len, n);
4866 mono_stats.new_object_count++;
4869 if (G_UNLIKELY (profile_allocs))
4870 mono_profiler_allocation (o, vtable->klass);
4876 * mono_string_new_utf16:
4877 * @text: a pointer to an utf16 string
4878 * @len: the length of the string
4880 * Returns: A newly created string object which contains @text.
4883 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4887 s = mono_string_new_size (domain, len);
4888 g_assert (s != NULL);
4890 memcpy (mono_string_chars (s), text, len * 2);
4896 * mono_string_new_size:
4897 * @text: a pointer to an utf16 string
4898 * @len: the length of the string
4900 * Returns: A newly created string object of @len
4903 mono_string_new_size (MonoDomain *domain, gint32 len)
4907 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4909 /* overflow ? can't fit it, can't allocate it! */
4911 mono_gc_out_of_memory (-1);
4913 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4916 #ifndef HAVE_SGEN_GC
4917 s = mono_object_allocate_ptrfree (size, vtable);
4921 s = mono_gc_alloc_string (vtable, size, len);
4923 #if NEED_TO_ZERO_PTRFREE
4926 if (G_UNLIKELY (profile_allocs))
4927 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4933 * mono_string_new_len:
4934 * @text: a pointer to an utf8 string
4935 * @length: number of bytes in @text to consider
4937 * Returns: A newly created string object which contains @text.
4940 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4942 GError *error = NULL;
4943 MonoString *o = NULL;
4945 glong items_written;
4947 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4950 o = mono_string_new_utf16 (domain, ut, items_written);
4952 g_error_free (error);
4961 * @text: a pointer to an utf8 string
4963 * Returns: A newly created string object which contains @text.
4966 mono_string_new (MonoDomain *domain, const char *text)
4968 GError *error = NULL;
4969 MonoString *o = NULL;
4971 glong items_written;
4976 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4979 o = mono_string_new_utf16 (domain, ut, items_written);
4981 g_error_free (error);
4984 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4989 MonoString *o = NULL;
4991 if (!g_utf8_validate (text, -1, &end))
4994 len = g_utf8_strlen (text, -1);
4995 o = mono_string_new_size (domain, len);
4996 str = mono_string_chars (o);
4998 while (text < end) {
4999 *str++ = g_utf8_get_char (text);
5000 text = g_utf8_next_char (text);
5007 * mono_string_new_wrapper:
5008 * @text: pointer to utf8 characters.
5010 * Helper function to create a string object from @text in the current domain.
5013 mono_string_new_wrapper (const char *text)
5015 MonoDomain *domain = mono_domain_get ();
5017 MONO_ARCH_SAVE_REGS;
5020 return mono_string_new (domain, text);
5027 * @class: the class of the value
5028 * @value: a pointer to the unboxed data
5030 * Returns: A newly created object which contains @value.
5033 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5039 g_assert (class->valuetype);
5040 if (mono_class_is_nullable (class))
5041 return mono_nullable_box (value, class);
5043 vtable = mono_class_vtable (domain, class);
5046 size = mono_class_instance_size (class);
5047 res = mono_object_new_alloc_specific (vtable);
5048 if (G_UNLIKELY (profile_allocs))
5049 mono_profiler_allocation (res, class);
5051 size = size - sizeof (MonoObject);
5054 g_assert (size == mono_class_value_size (class, NULL));
5055 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5057 #if NO_UNALIGNED_ACCESS
5058 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5062 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5065 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5068 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5071 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5074 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5078 if (class->has_finalize)
5079 mono_object_register_finalizer (res);
5085 * @dest: destination pointer
5086 * @src: source pointer
5087 * @klass: a valuetype class
5089 * Copy a valuetype from @src to @dest. This function must be used
5090 * when @klass contains references fields.
5093 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5095 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5099 * mono_value_copy_array:
5100 * @dest: destination array
5101 * @dest_idx: index in the @dest array
5102 * @src: source pointer
5103 * @count: number of items
5105 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5106 * This function must be used when @klass contains references fields.
5107 * Overlap is handled.
5110 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5112 int size = mono_array_element_size (dest->obj.vtable->klass);
5113 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5114 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5115 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5119 * mono_object_get_domain:
5120 * @obj: object to query
5122 * Returns: the MonoDomain where the object is hosted
5125 mono_object_get_domain (MonoObject *obj)
5127 return mono_object_domain (obj);
5131 * mono_object_get_class:
5132 * @obj: object to query
5134 * Returns: the MonOClass of the object.
5137 mono_object_get_class (MonoObject *obj)
5139 return mono_object_class (obj);
5142 * mono_object_get_size:
5143 * @o: object to query
5145 * Returns: the size, in bytes, of @o
5148 mono_object_get_size (MonoObject* o)
5150 MonoClass* klass = mono_object_class (o);
5151 if (klass == mono_defaults.string_class) {
5152 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5153 } else if (o->vtable->rank) {
5154 MonoArray *array = (MonoArray*)o;
5155 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5156 if (array->bounds) {
5159 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5163 return mono_class_instance_size (klass);
5168 * mono_object_unbox:
5169 * @obj: object to unbox
5171 * Returns: a pointer to the start of the valuetype boxed in this
5174 * This method will assert if the object passed is not a valuetype.
5177 mono_object_unbox (MonoObject *obj)
5179 /* add assert for valuetypes? */
5180 g_assert (obj->vtable->klass->valuetype);
5181 return ((char*)obj) + sizeof (MonoObject);
5185 * mono_object_isinst:
5187 * @klass: a pointer to a class
5189 * Returns: @obj if @obj is derived from @klass
5192 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5195 mono_class_init (klass);
5197 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5198 return mono_object_isinst_mbyref (obj, klass);
5203 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5207 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5216 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5217 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5221 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5222 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5225 MonoClass *oklass = vt->klass;
5226 if (oklass == mono_defaults.transparent_proxy_class)
5227 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5229 mono_class_setup_supertypes (klass);
5230 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5234 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5236 MonoDomain *domain = mono_domain_get ();
5238 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5239 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5240 MonoMethod *im = NULL;
5243 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5244 im = mono_object_get_virtual_method (rp, im);
5247 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5250 res = mono_runtime_invoke (im, rp, pa, NULL);
5252 if (*(MonoBoolean *) mono_object_unbox(res)) {
5253 /* Update the vtable of the remote type, so it can safely cast to this new type */
5254 mono_upgrade_remote_class (domain, obj, klass);
5263 * mono_object_castclass_mbyref:
5265 * @klass: a pointer to a class
5267 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5270 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5272 if (!obj) return NULL;
5273 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5275 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5277 "InvalidCastException"));
5282 MonoDomain *orig_domain;
5288 str_lookup (MonoDomain *domain, gpointer user_data)
5290 LDStrInfo *info = user_data;
5291 if (info->res || domain == info->orig_domain)
5293 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5299 mono_string_get_pinned (MonoString *str)
5303 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5304 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5306 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5307 news->length = mono_string_length (str);
5313 #define mono_string_get_pinned(str) (str)
5317 mono_string_is_interned_lookup (MonoString *str, int insert)
5319 MonoGHashTable *ldstr_table;
5323 domain = ((MonoObject *)str)->vtable->domain;
5324 ldstr_table = domain->ldstr_table;
5326 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5331 str = mono_string_get_pinned (str);
5333 mono_g_hash_table_insert (ldstr_table, str, str);
5337 LDStrInfo ldstr_info;
5338 ldstr_info.orig_domain = domain;
5339 ldstr_info.ins = str;
5340 ldstr_info.res = NULL;
5342 mono_domain_foreach (str_lookup, &ldstr_info);
5343 if (ldstr_info.res) {
5345 * the string was already interned in some other domain:
5346 * intern it in the current one as well.
5348 mono_g_hash_table_insert (ldstr_table, str, str);
5358 * mono_string_is_interned:
5359 * @o: String to probe
5361 * Returns whether the string has been interned.
5364 mono_string_is_interned (MonoString *o)
5366 return mono_string_is_interned_lookup (o, FALSE);
5370 * mono_string_intern:
5371 * @o: String to intern
5373 * Interns the string passed.
5374 * Returns: The interned string.
5377 mono_string_intern (MonoString *str)
5379 return mono_string_is_interned_lookup (str, TRUE);
5384 * @domain: the domain where the string will be used.
5385 * @image: a metadata context
5386 * @idx: index into the user string table.
5388 * Implementation for the ldstr opcode.
5389 * Returns: a loaded string from the @image/@idx combination.
5392 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5394 MONO_ARCH_SAVE_REGS;
5396 if (image->dynamic) {
5397 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5400 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5401 return NULL; /*FIXME we should probably be raising an exception here*/
5402 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5407 * mono_ldstr_metadata_sig
5408 * @domain: the domain for the string
5409 * @sig: the signature of a metadata string
5411 * Returns: a MonoString for a string stored in the metadata
5414 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5416 const char *str = sig;
5417 MonoString *o, *interned;
5420 len2 = mono_metadata_decode_blob_size (str, &str);
5423 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5424 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5427 guint16 *p2 = (guint16*)mono_string_chars (o);
5428 for (i = 0; i < len2; ++i) {
5429 *p2 = GUINT16_FROM_LE (*p2);
5435 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5437 /* o will get garbage collected */
5441 o = mono_string_get_pinned (o);
5443 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5450 * mono_string_to_utf8:
5451 * @s: a System.String
5453 * Returns the UTF8 representation for @s.
5454 * The resulting buffer needs to be freed with mono_free().
5456 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5459 mono_string_to_utf8 (MonoString *s)
5462 char *result = mono_string_to_utf8_checked (s, &error);
5464 if (!mono_error_ok (&error))
5465 mono_error_raise_exception (&error);
5470 * mono_string_to_utf8_checked:
5471 * @s: a System.String
5472 * @error: a MonoError.
5474 * Converts a MonoString to its UTF8 representation. May fail; check
5475 * @error to determine whether the conversion was successful.
5476 * The resulting buffer should be freed with mono_free().
5479 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5483 GError *gerror = NULL;
5485 mono_error_init (error);
5491 return g_strdup ("");
5493 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5495 mono_error_set_argument (error, "string", "%s", gerror->message);
5496 g_error_free (gerror);
5499 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5500 if (s->length > written) {
5501 /* allocate the total length and copy the part of the string that has been converted */
5502 char *as2 = g_malloc0 (s->length);
5503 memcpy (as2, as, written);
5512 * mono_string_to_utf8_ignore:
5515 * Converts a MonoString to its UTF8 representation. Will ignore
5516 * invalid surrogate pairs.
5517 * The resulting buffer should be freed with mono_free().
5521 mono_string_to_utf8_ignore (MonoString *s)
5530 return g_strdup ("");
5532 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5534 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5535 if (s->length > written) {
5536 /* allocate the total length and copy the part of the string that has been converted */
5537 char *as2 = g_malloc0 (s->length);
5538 memcpy (as2, as, written);
5547 * mono_string_to_utf8_image_ignore:
5548 * @s: a System.String
5550 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5553 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5555 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5559 * mono_string_to_utf8_mp_ignore:
5560 * @s: a System.String
5562 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5565 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5567 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5572 * mono_string_to_utf16:
5575 * Return an null-terminated array of the utf-16 chars
5576 * contained in @s. The result must be freed with g_free().
5577 * This is a temporary helper until our string implementation
5578 * is reworked to always include the null terminating char.
5581 mono_string_to_utf16 (MonoString *s)
5588 as = g_malloc ((s->length * 2) + 2);
5589 as [(s->length * 2)] = '\0';
5590 as [(s->length * 2) + 1] = '\0';
5593 return (gunichar2 *)(as);
5596 memcpy (as, mono_string_chars(s), s->length * 2);
5597 return (gunichar2 *)(as);
5601 * mono_string_from_utf16:
5602 * @data: the UTF16 string (LPWSTR) to convert
5604 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5606 * Returns: a MonoString.
5609 mono_string_from_utf16 (gunichar2 *data)
5611 MonoDomain *domain = mono_domain_get ();
5617 while (data [len]) len++;
5619 return mono_string_new_utf16 (domain, data, len);
5624 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5631 r = mono_string_to_utf8_ignore (s);
5633 r = mono_string_to_utf8_checked (s, error);
5634 if (!mono_error_ok (error))
5641 len = strlen (r) + 1;
5643 mp_s = mono_mempool_alloc (mp, len);
5645 mp_s = mono_image_alloc (image, len);
5647 memcpy (mp_s, r, len);
5655 * mono_string_to_utf8_image:
5656 * @s: a System.String
5658 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5661 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5663 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5667 * mono_string_to_utf8_mp:
5668 * @s: a System.String
5670 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5673 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5675 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5679 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5682 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5684 eh_callbacks = *cbs;
5687 MonoRuntimeExceptionHandlingCallbacks *
5688 mono_get_eh_callbacks (void)
5690 return &eh_callbacks;
5694 * mono_raise_exception:
5695 * @ex: exception object
5697 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5700 mono_raise_exception (MonoException *ex)
5703 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5704 * that will cause gcc to omit the function epilog, causing problems when
5705 * the JIT tries to walk the stack, since the return address on the stack
5706 * will point into the next function in the executable, not this one.
5708 eh_callbacks.mono_raise_exception (ex);
5712 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5714 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5718 * mono_wait_handle_new:
5719 * @domain: Domain where the object will be created
5720 * @handle: Handle for the wait handle
5722 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5725 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5727 MonoWaitHandle *res;
5728 gpointer params [1];
5729 static MonoMethod *handle_set;
5731 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5733 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5735 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5737 params [0] = &handle;
5738 mono_runtime_invoke (handle_set, res, params, NULL);
5744 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5746 static MonoClassField *f_os_handle;
5747 static MonoClassField *f_safe_handle;
5749 if (!f_os_handle && !f_safe_handle) {
5750 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5751 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5756 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5760 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5767 mono_runtime_capture_context (MonoDomain *domain)
5769 RuntimeInvokeFunction runtime_invoke;
5771 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5772 MonoMethod *method = mono_get_context_capture_method ();
5773 MonoMethod *wrapper;
5776 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5777 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5778 domain->capture_context_method = mono_compile_method (method);
5781 runtime_invoke = domain->capture_context_runtime_invoke;
5783 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5786 * mono_async_result_new:
5787 * @domain:domain where the object will be created.
5788 * @handle: wait handle.
5789 * @state: state to pass to AsyncResult
5790 * @data: C closure data.
5792 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5793 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5797 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5799 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5800 MonoObject *context = mono_runtime_capture_context (domain);
5801 /* we must capture the execution context from the original thread */
5803 MONO_OBJECT_SETREF (res, execution_context, context);
5804 /* note: result may be null if the flow is suppressed */
5808 MONO_OBJECT_SETREF (res, object_data, object_data);
5809 MONO_OBJECT_SETREF (res, async_state, state);
5811 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5813 res->sync_completed = FALSE;
5814 res->completed = FALSE;
5820 mono_message_init (MonoDomain *domain,
5821 MonoMethodMessage *this,
5822 MonoReflectionMethod *method,
5823 MonoArray *out_args)
5825 static MonoClass *object_array_klass;
5826 static MonoClass *byte_array_klass;
5827 static MonoClass *string_array_klass;
5828 MonoMethodSignature *sig = mono_method_signature (method->method);
5834 if (!object_array_klass) {
5837 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5839 byte_array_klass = klass;
5841 klass = mono_array_class_get (mono_defaults.string_class, 1);
5843 string_array_klass = klass;
5845 klass = mono_array_class_get (mono_defaults.object_class, 1);
5848 mono_atomic_store_release (&object_array_klass, klass);
5851 MONO_OBJECT_SETREF (this, method, method);
5853 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5854 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5855 this->async_result = NULL;
5856 this->call_type = CallType_Sync;
5858 names = g_new (char *, sig->param_count);
5859 mono_method_get_param_names (method->method, (const char **) names);
5860 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5862 for (i = 0; i < sig->param_count; i++) {
5863 name = mono_string_new (domain, names [i]);
5864 mono_array_setref (this->names, i, name);
5868 for (i = 0, j = 0; i < sig->param_count; i++) {
5869 if (sig->params [i]->byref) {
5871 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5872 mono_array_setref (this->args, i, arg);
5876 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5880 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5883 mono_array_set (this->arg_types, guint8, i, arg_type);
5888 * mono_remoting_invoke:
5889 * @real_proxy: pointer to a RealProxy object
5890 * @msg: The MonoMethodMessage to execute
5891 * @exc: used to store exceptions
5892 * @out_args: used to store output arguments
5894 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5895 * IMessage interface and it is not trivial to extract results from there. So
5896 * we call an helper method PrivateInvoke instead of calling
5897 * RealProxy::Invoke() directly.
5899 * Returns: the result object.
5902 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5903 MonoObject **exc, MonoArray **out_args)
5905 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5908 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5911 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5913 real_proxy->vtable->domain->private_invoke_method = im;
5916 pa [0] = real_proxy;
5921 return mono_runtime_invoke (im, NULL, pa, exc);
5925 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5926 MonoObject **exc, MonoArray **out_args)
5928 static MonoClass *object_array_klass;
5931 MonoMethodSignature *sig;
5933 int i, j, outarg_count = 0;
5935 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5937 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5938 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5939 target = tp->rp->unwrapped_server;
5941 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5945 domain = mono_domain_get ();
5946 method = msg->method->method;
5947 sig = mono_method_signature (method);
5949 for (i = 0; i < sig->param_count; i++) {
5950 if (sig->params [i]->byref)
5954 if (!object_array_klass) {
5957 klass = mono_array_class_get (mono_defaults.object_class, 1);
5960 mono_memory_barrier ();
5961 object_array_klass = klass;
5964 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5965 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5968 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5970 for (i = 0, j = 0; i < sig->param_count; i++) {
5971 if (sig->params [i]->byref) {
5973 arg = mono_array_get (msg->args, gpointer, i);
5974 mono_array_setref (*out_args, j, arg);
5983 * mono_object_to_string:
5985 * @exc: Any exception thrown by ToString (). May be NULL.
5987 * Returns: the result of calling ToString () on an object.
5990 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5992 static MonoMethod *to_string = NULL;
5998 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6000 method = mono_object_get_virtual_method (obj, to_string);
6002 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
6006 * mono_print_unhandled_exception:
6007 * @exc: The exception
6009 * Prints the unhandled exception.
6012 mono_print_unhandled_exception (MonoObject *exc)
6015 char *message = (char*)"";
6016 gboolean free_message = FALSE;
6019 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6020 message = g_strdup ("OutOfMemoryException");
6021 free_message = TRUE;
6024 if (((MonoException*)exc)->native_trace_ips) {
6025 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6026 free_message = TRUE;
6028 str = mono_object_to_string (exc, NULL);
6030 message = mono_string_to_utf8_checked (str, &error);
6031 if (!mono_error_ok (&error)) {
6032 mono_error_cleanup (&error);
6033 message = (char *) "";
6035 free_message = TRUE;
6042 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6043 * exc->vtable->klass->name, message);
6045 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6052 * mono_delegate_ctor:
6053 * @this: pointer to an uninitialized delegate object
6054 * @target: target object
6055 * @addr: pointer to native code
6058 * Initialize a delegate and sets a specific method, not the one
6059 * associated with addr. This is useful when sharing generic code.
6060 * In that case addr will most probably not be associated with the
6061 * correct instantiation of the method.
6064 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6066 MonoDelegate *delegate = (MonoDelegate *)this;
6073 delegate->method = method;
6075 class = this->vtable->klass;
6076 mono_stats.delegate_creations++;
6078 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6080 method = mono_marshal_get_remoting_invoke (method);
6081 delegate->method_ptr = mono_compile_method (method);
6082 MONO_OBJECT_SETREF (delegate, target, target);
6083 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6084 method = mono_marshal_get_unbox_wrapper (method);
6085 delegate->method_ptr = mono_compile_method (method);
6086 MONO_OBJECT_SETREF (delegate, target, target);
6088 delegate->method_ptr = addr;
6089 MONO_OBJECT_SETREF (delegate, target, target);
6092 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6096 * mono_delegate_ctor:
6097 * @this: pointer to an uninitialized delegate object
6098 * @target: target object
6099 * @addr: pointer to native code
6101 * This is used to initialize a delegate.
6104 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6106 MonoDomain *domain = mono_domain_get ();
6108 MonoMethod *method = NULL;
6112 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6114 if (!ji && domain != mono_get_root_domain ())
6115 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6117 method = ji->method;
6118 g_assert (!method->klass->generic_container);
6121 mono_delegate_ctor_with_method (this, target, addr, method);
6125 * mono_method_call_message_new:
6126 * @method: method to encapsulate
6127 * @params: parameters to the method
6128 * @invoke: optional, delegate invoke.
6129 * @cb: async callback delegate.
6130 * @state: state passed to the async callback.
6132 * Translates arguments pointers into a MonoMethodMessage.
6135 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6136 MonoDelegate **cb, MonoObject **state)
6138 MonoDomain *domain = mono_domain_get ();
6139 MonoMethodSignature *sig = mono_method_signature (method);
6140 MonoMethodMessage *msg;
6143 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6146 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6147 count = sig->param_count - 2;
6149 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6150 count = sig->param_count;
6153 for (i = 0; i < count; i++) {
6158 if (sig->params [i]->byref)
6159 vpos = *((gpointer *)params [i]);
6163 type = sig->params [i]->type;
6164 class = mono_class_from_mono_type (sig->params [i]);
6166 if (class->valuetype)
6167 arg = mono_value_box (domain, class, vpos);
6169 arg = *((MonoObject **)vpos);
6171 mono_array_setref (msg->args, i, arg);
6174 if (cb != NULL && state != NULL) {
6175 *cb = *((MonoDelegate **)params [i]);
6177 *state = *((MonoObject **)params [i]);
6184 * mono_method_return_message_restore:
6186 * Restore results from message based processing back to arguments pointers
6189 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6191 MonoMethodSignature *sig = mono_method_signature (method);
6192 int i, j, type, size, out_len;
6194 if (out_args == NULL)
6196 out_len = mono_array_length (out_args);
6200 for (i = 0, j = 0; i < sig->param_count; i++) {
6201 MonoType *pt = sig->params [i];
6206 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6208 arg = mono_array_get (out_args, gpointer, j);
6211 g_assert (type != MONO_TYPE_VOID);
6213 if (MONO_TYPE_IS_REFERENCE (pt)) {
6214 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6217 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6218 size = mono_class_value_size (class, NULL);
6219 if (class->has_references)
6220 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6222 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6224 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6225 mono_gc_bzero (*((gpointer *)params [i]), size);
6235 * mono_load_remote_field:
6236 * @this: pointer to an object
6237 * @klass: klass of the object containing @field
6238 * @field: the field to load
6239 * @res: a storage to store the result
6241 * This method is called by the runtime on attempts to load fields of
6242 * transparent proxy objects. @this points to such TP, @klass is the class of
6243 * the object containing @field. @res is a storage location which can be
6244 * used to store the result.
6246 * Returns: an address pointing to the value of field.
6249 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6251 static MonoMethod *getter = NULL;
6252 MonoDomain *domain = mono_domain_get ();
6253 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6254 MonoClass *field_class;
6255 MonoMethodMessage *msg;
6256 MonoArray *out_args;
6260 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6261 g_assert (res != NULL);
6263 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6264 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6269 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6273 field_class = mono_class_from_mono_type (field->type);
6275 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6276 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6277 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6279 full_name = mono_type_get_full_name (klass);
6280 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6281 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6284 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6286 if (exc) mono_raise_exception ((MonoException *)exc);
6288 if (mono_array_length (out_args) == 0)
6291 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6293 if (field_class->valuetype) {
6294 return ((char *)*res) + sizeof (MonoObject);
6300 * mono_load_remote_field_new:
6305 * Missing documentation.
6308 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6310 static MonoMethod *getter = NULL;
6311 MonoDomain *domain = mono_domain_get ();
6312 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6313 MonoClass *field_class;
6314 MonoMethodMessage *msg;
6315 MonoArray *out_args;
6316 MonoObject *exc, *res;
6319 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6321 field_class = mono_class_from_mono_type (field->type);
6323 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6325 if (field_class->valuetype) {
6326 res = mono_object_new (domain, field_class);
6327 val = ((gchar *) res) + sizeof (MonoObject);
6331 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6336 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6340 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6341 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6343 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6345 full_name = mono_type_get_full_name (klass);
6346 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6347 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6350 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6352 if (exc) mono_raise_exception ((MonoException *)exc);
6354 if (mono_array_length (out_args) == 0)
6357 res = mono_array_get (out_args, MonoObject *, 0);
6363 * mono_store_remote_field:
6364 * @this: pointer to an object
6365 * @klass: klass of the object containing @field
6366 * @field: the field to load
6367 * @val: the value/object to store
6369 * This method is called by the runtime on attempts to store fields of
6370 * transparent proxy objects. @this points to such TP, @klass is the class of
6371 * the object containing @field. @val is the new value to store in @field.
6374 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6376 static MonoMethod *setter = NULL;
6377 MonoDomain *domain = mono_domain_get ();
6378 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6379 MonoClass *field_class;
6380 MonoMethodMessage *msg;
6381 MonoArray *out_args;
6386 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6388 field_class = mono_class_from_mono_type (field->type);
6390 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6391 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6392 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6397 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6401 if (field_class->valuetype)
6402 arg = mono_value_box (domain, field_class, val);
6404 arg = *((MonoObject **)val);
6407 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6408 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6410 full_name = mono_type_get_full_name (klass);
6411 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6412 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6413 mono_array_setref (msg->args, 2, arg);
6416 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6418 if (exc) mono_raise_exception ((MonoException *)exc);
6422 * mono_store_remote_field_new:
6428 * Missing documentation
6431 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6433 static MonoMethod *setter = NULL;
6434 MonoDomain *domain = mono_domain_get ();
6435 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6436 MonoClass *field_class;
6437 MonoMethodMessage *msg;
6438 MonoArray *out_args;
6442 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6444 field_class = mono_class_from_mono_type (field->type);
6446 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6447 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6448 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6453 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6457 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6458 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6460 full_name = mono_type_get_full_name (klass);
6461 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6462 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6463 mono_array_setref (msg->args, 2, arg);
6466 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6468 if (exc) mono_raise_exception ((MonoException *)exc);
6472 * mono_create_ftnptr:
6474 * Given a function address, create a function descriptor for it.
6475 * This is only needed on some platforms.
6478 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6480 return callbacks.create_ftnptr (domain, addr);
6484 * mono_get_addr_from_ftnptr:
6486 * Given a pointer to a function descriptor, return the function address.
6487 * This is only needed on some platforms.
6490 mono_get_addr_from_ftnptr (gpointer descr)
6492 return callbacks.get_addr_from_ftnptr (descr);
6496 * mono_string_chars:
6499 * Returns a pointer to the UCS16 characters stored in the MonoString
6502 mono_string_chars (MonoString *s)
6508 * mono_string_length:
6511 * Returns the lenght in characters of the string
6514 mono_string_length (MonoString *s)
6520 * mono_array_length:
6521 * @array: a MonoArray*
6523 * Returns the total number of elements in the array. This works for
6524 * both vectors and multidimensional arrays.
6527 mono_array_length (MonoArray *array)
6529 return array->max_length;
6533 * mono_array_addr_with_size:
6534 * @array: a MonoArray*
6535 * @size: size of the array elements
6536 * @idx: index into the array
6538 * Returns the address of the @idx element in the array.
6541 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6543 return ((char*)(array)->vector) + size * idx;