2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/threadpool.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internal.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include "cominterop.h"
50 #define NEED_TO_ZERO_PTRFREE 1
51 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
52 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
53 #ifdef HAVE_GC_GCJ_MALLOC
54 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
62 #define GC_NO_DESCRIPTOR (NULL)
63 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
65 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
67 #define NEED_TO_ZERO_PTRFREE 1
68 #define GC_NO_DESCRIPTOR (NULL)
69 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
70 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
71 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
75 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
76 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
79 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
82 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
85 free_main_args (void);
88 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
91 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
92 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
93 static CRITICAL_SECTION ldstr_section;
95 static gboolean profile_allocs = TRUE;
98 mono_runtime_object_init (MonoObject *this)
100 MonoMethod *method = NULL;
101 MonoClass *klass = this->vtable->klass;
103 method = mono_class_get_method_from_name (klass, ".ctor", 0);
105 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
107 if (method->klass->valuetype)
108 this = mono_object_unbox (this);
109 mono_runtime_invoke (method, this, NULL, NULL);
112 /* The pseudo algorithm for type initialization from the spec
113 Note it doesn't say anything about domains - only threads.
115 2. If the type is initialized you are done.
116 2.1. If the type is not yet initialized, try to take an
118 2.2. If successful, record this thread as responsible for
119 initializing the type and proceed to step 2.3.
120 2.2.1. If not, see whether this thread or any thread
121 waiting for this thread to complete already holds the lock.
122 2.2.2. If so, return since blocking would create a deadlock. This thread
123 will now see an incompletely initialized state for the type,
124 but no deadlock will arise.
125 2.2.3 If not, block until the type is initialized then return.
126 2.3 Initialize the parent type and then all interfaces implemented
128 2.4 Execute the type initialization code for this type.
129 2.5 Mark the type as initialized, release the initialization lock,
130 awaken any threads waiting for this type to be initialized,
137 guint32 initializing_tid;
138 guint32 waiting_count;
140 CRITICAL_SECTION initialization_section;
141 } TypeInitializationLock;
143 /* for locking access to type_initialization_hash and blocked_thread_hash */
144 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
145 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
146 static CRITICAL_SECTION type_initialization_section;
148 /* from vtable to lock */
149 static GHashTable *type_initialization_hash;
151 /* from thread id to thread id being waited on */
152 static GHashTable *blocked_thread_hash;
155 static MonoThread *main_thread;
157 /* Functions supplied by the runtime */
158 static MonoRuntimeCallbacks callbacks;
161 * mono_thread_set_main:
162 * @thread: thread to set as the main thread
164 * This function can be used to instruct the runtime to treat @thread
165 * as the main thread, ie, the thread that would normally execute the Main()
166 * method. This basically means that at the end of @thread, the runtime will
167 * wait for the existing foreground threads to quit and other such details.
170 mono_thread_set_main (MonoThread *thread)
172 static gboolean registered = FALSE;
175 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
179 main_thread = thread;
183 mono_thread_get_main (void)
189 mono_type_initialization_init (void)
191 InitializeCriticalSection (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 InitializeCriticalSection (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 DeleteCriticalSection (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 DeleteCriticalSection (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MonoDomain *domain = vtable->domain;
224 MonoClass *klass = vtable->klass;
228 if (!vtable->init_failed)
229 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
232 * If the initializing thread was rudely aborted, the exception is not stored
236 mono_domain_lock (domain);
237 if (domain->type_init_exception_hash)
238 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
239 mono_domain_unlock (domain);
242 if (klass->name_space && *klass->name_space)
243 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
245 full_name = g_strdup (klass->name);
246 ex = mono_get_exception_type_initialization (full_name, NULL);
253 * mono_runtime_class_init:
254 * @vtable: vtable that needs to be initialized
256 * This routine calls the class constructor for @vtable.
259 mono_runtime_class_init (MonoVTable *vtable)
261 mono_runtime_class_init_full (vtable, TRUE);
265 * mono_runtime_class_init_full:
266 * @vtable that neeeds to be initialized
267 * @raise_exception is TRUE, exceptions are raised intead of returned
271 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
274 MonoException *exc_to_throw;
275 MonoMethod *method = NULL;
281 if (vtable->initialized)
285 klass = vtable->klass;
287 if (!klass->image->checked_module_cctor) {
288 mono_image_check_for_module_cctor (klass->image);
289 if (klass->image->has_module_cctor) {
290 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
291 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
294 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
299 method = mono_class_get_cctor (klass);
302 MonoDomain *domain = vtable->domain;
303 TypeInitializationLock *lock;
304 guint32 tid = GetCurrentThreadId();
305 int do_initialization = 0;
306 MonoDomain *last_domain = NULL;
308 mono_type_initialization_lock ();
309 /* double check... */
310 if (vtable->initialized) {
311 mono_type_initialization_unlock ();
314 if (vtable->init_failed) {
315 mono_type_initialization_unlock ();
317 /* The type initialization already failed once, rethrow the same exception */
319 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
320 return get_type_init_exception_for_vtable (vtable);
322 lock = g_hash_table_lookup (type_initialization_hash, vtable);
324 /* This thread will get to do the initialization */
325 if (mono_domain_get () != domain) {
326 /* Transfer into the target domain */
327 last_domain = mono_domain_get ();
328 if (!mono_domain_set (domain, FALSE)) {
329 vtable->initialized = 1;
330 mono_type_initialization_unlock ();
332 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
333 return mono_get_exception_appdomain_unloaded ();
336 lock = g_malloc (sizeof(TypeInitializationLock));
337 InitializeCriticalSection (&lock->initialization_section);
338 lock->initializing_tid = tid;
339 lock->waiting_count = 1;
341 /* grab the vtable lock while this thread still owns type_initialization_section */
342 EnterCriticalSection (&lock->initialization_section);
343 g_hash_table_insert (type_initialization_hash, vtable, lock);
344 do_initialization = 1;
347 TypeInitializationLock *pending_lock;
349 if (lock->initializing_tid == tid || lock->done) {
350 mono_type_initialization_unlock ();
353 /* see if the thread doing the initialization is already blocked on this thread */
354 blocked = GUINT_TO_POINTER (lock->initializing_tid);
355 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
356 if (pending_lock->initializing_tid == tid) {
357 if (!pending_lock->done) {
358 mono_type_initialization_unlock ();
361 /* the thread doing the initialization is blocked on this thread,
362 but on a lock that has already been freed. It just hasn't got
367 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
369 ++lock->waiting_count;
370 /* record the fact that we are waiting on the initializing thread */
371 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
373 mono_type_initialization_unlock ();
375 if (do_initialization) {
376 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
378 /* If the initialization failed, mark the class as unusable. */
379 /* Avoid infinite loops */
381 (klass->image == mono_defaults.corlib &&
382 !strcmp (klass->name_space, "System") &&
383 !strcmp (klass->name, "TypeInitializationException")))) {
384 vtable->init_failed = 1;
386 if (klass->name_space && *klass->name_space)
387 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
389 full_name = g_strdup (klass->name);
390 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
394 * Store the exception object so it could be thrown on subsequent
397 mono_domain_lock (domain);
398 if (!domain->type_init_exception_hash)
399 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
400 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
401 mono_domain_unlock (domain);
405 mono_domain_set (last_domain, TRUE);
407 LeaveCriticalSection (&lock->initialization_section);
409 /* this just blocks until the initializing thread is done */
410 EnterCriticalSection (&lock->initialization_section);
411 LeaveCriticalSection (&lock->initialization_section);
414 mono_type_initialization_lock ();
415 if (lock->initializing_tid != tid)
416 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
417 --lock->waiting_count;
418 if (lock->waiting_count == 0) {
419 DeleteCriticalSection (&lock->initialization_section);
420 g_hash_table_remove (type_initialization_hash, vtable);
423 mono_memory_barrier ();
424 if (!vtable->init_failed)
425 vtable->initialized = 1;
426 mono_type_initialization_unlock ();
428 if (vtable->init_failed) {
429 /* Either we were the initializing thread or we waited for the initialization */
431 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
432 return get_type_init_exception_for_vtable (vtable);
435 vtable->initialized = 1;
442 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
444 MonoVTable *vtable = (MonoVTable*)key;
446 TypeInitializationLock *lock = (TypeInitializationLock*) value;
447 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
450 * Have to set this since it cannot be set by the normal code in
451 * mono_runtime_class_init (). In this case, the exception object is not stored,
452 * and get_type_init_exception_for_class () needs to be aware of this.
454 vtable->init_failed = 1;
455 LeaveCriticalSection (&lock->initialization_section);
456 --lock->waiting_count;
457 if (lock->waiting_count == 0) {
458 DeleteCriticalSection (&lock->initialization_section);
467 mono_release_type_locks (MonoInternalThread *thread)
469 mono_type_initialization_lock ();
470 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
471 mono_type_initialization_unlock ();
475 default_trampoline (MonoMethod *method)
481 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
483 g_assert_not_reached ();
489 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
491 g_error ("remoting not installed");
496 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
498 g_assert_not_reached ();
502 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
503 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
504 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
505 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
506 static MonoImtThunkBuilder imt_thunk_builder = NULL;
507 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
508 #if (MONO_IMT_SIZE > 32)
509 #error "MONO_IMT_SIZE cannot be larger than 32"
513 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
515 memcpy (&callbacks, cbs, sizeof (*cbs));
518 MonoRuntimeCallbacks*
519 mono_get_runtime_callbacks (void)
525 mono_install_trampoline (MonoTrampoline func)
527 arch_create_jit_trampoline = func? func: default_trampoline;
531 mono_install_jump_trampoline (MonoJumpTrampoline func)
533 arch_create_jump_trampoline = func? func: default_jump_trampoline;
537 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
539 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
543 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
545 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
549 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
550 imt_thunk_builder = func;
553 static MonoCompileFunc default_mono_compile_method = NULL;
556 * mono_install_compile_method:
557 * @func: function to install
559 * This is a VM internal routine
562 mono_install_compile_method (MonoCompileFunc func)
564 default_mono_compile_method = func;
568 * mono_compile_method:
569 * @method: The method to compile.
571 * This JIT-compiles the method, and returns the pointer to the native code
575 mono_compile_method (MonoMethod *method)
577 if (!default_mono_compile_method) {
578 g_error ("compile method called on uninitialized runtime");
581 return default_mono_compile_method (method);
585 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
587 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
591 mono_runtime_create_delegate_trampoline (MonoClass *klass)
593 return arch_create_delegate_trampoline (mono_domain_get (), klass);
596 static MonoFreeMethodFunc default_mono_free_method = NULL;
599 * mono_install_free_method:
600 * @func: pointer to the MonoFreeMethodFunc used to release a method
602 * This is an internal VM routine, it is used for the engines to
603 * register a handler to release the resources associated with a method.
605 * Methods are freed when no more references to the delegate that holds
609 mono_install_free_method (MonoFreeMethodFunc func)
611 default_mono_free_method = func;
615 * mono_runtime_free_method:
616 * @domain; domain where the method is hosted
617 * @method: method to release
619 * This routine is invoked to free the resources associated with
620 * a method that has been JIT compiled. This is used to discard
621 * methods that were used only temporarily (for example, used in marshalling)
625 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
627 if (default_mono_free_method != NULL)
628 default_mono_free_method (domain, method);
630 mono_method_clear_object (domain, method);
632 mono_free_method (method);
636 * The vtables in the root appdomain are assumed to be reachable by other
637 * roots, and we don't use typed allocation in the other domains.
640 /* The sync block is no longer a GC pointer */
641 #define GC_HEADER_BITMAP (0)
643 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
646 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
648 MonoClassField *field;
654 max_size = mono_class_data_size (class) / sizeof (gpointer);
656 max_size = class->instance_size / sizeof (gpointer);
657 if (max_size > size) {
658 g_assert (offset <= 0);
659 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
664 /*An Ephemeron cannot be marked by sgen*/
665 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
667 memset (bitmap, 0, size / 8);
672 for (p = class; p != NULL; p = p->parent) {
673 gpointer iter = NULL;
674 while ((field = mono_class_get_fields (p, &iter))) {
678 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
680 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
683 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
686 /* FIXME: should not happen, flag as type load error */
687 if (field->type->byref)
690 if (static_fields && field->offset == -1)
694 pos = field->offset / sizeof (gpointer);
697 type = mono_type_get_underlying_type (field->type);
698 switch (type->type) {
701 case MONO_TYPE_FNPTR:
703 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
708 if (class->image != mono_defaults.corlib)
711 case MONO_TYPE_STRING:
712 case MONO_TYPE_SZARRAY:
713 case MONO_TYPE_CLASS:
714 case MONO_TYPE_OBJECT:
715 case MONO_TYPE_ARRAY:
716 g_assert ((field->offset % sizeof(gpointer)) == 0);
718 g_assert (pos < size || pos <= max_size);
719 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
720 *max_set = MAX (*max_set, pos);
722 case MONO_TYPE_GENERICINST:
723 if (!mono_type_generic_inst_is_valuetype (type)) {
724 g_assert ((field->offset % sizeof(gpointer)) == 0);
726 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
727 *max_set = MAX (*max_set, pos);
732 case MONO_TYPE_VALUETYPE: {
733 MonoClass *fclass = mono_class_from_mono_type (field->type);
734 if (fclass->has_references) {
735 /* remove the object header */
736 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
750 case MONO_TYPE_BOOLEAN:
754 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
765 * mono_class_compute_bitmap:
767 * Mono internal function to compute a bitmap of reference fields in a class.
770 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
772 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
777 * similar to the above, but sets the bits in the bitmap for any non-ref field
778 * and ignores static fields
781 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
783 MonoClassField *field;
788 max_size = class->instance_size / sizeof (gpointer);
789 if (max_size >= size) {
790 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
793 for (p = class; p != NULL; p = p->parent) {
794 gpointer iter = NULL;
795 while ((field = mono_class_get_fields (p, &iter))) {
798 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
800 /* FIXME: should not happen, flag as type load error */
801 if (field->type->byref)
804 pos = field->offset / sizeof (gpointer);
807 type = mono_type_get_underlying_type (field->type);
808 switch (type->type) {
809 #if SIZEOF_VOID_P == 8
813 case MONO_TYPE_FNPTR:
818 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
819 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
820 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
823 #if SIZEOF_VOID_P == 4
827 case MONO_TYPE_FNPTR:
832 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
833 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
834 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
840 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
841 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
842 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
845 case MONO_TYPE_BOOLEAN:
848 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
850 case MONO_TYPE_STRING:
851 case MONO_TYPE_SZARRAY:
852 case MONO_TYPE_CLASS:
853 case MONO_TYPE_OBJECT:
854 case MONO_TYPE_ARRAY:
856 case MONO_TYPE_GENERICINST:
857 if (!mono_type_generic_inst_is_valuetype (type)) {
862 case MONO_TYPE_VALUETYPE: {
863 MonoClass *fclass = mono_class_from_mono_type (field->type);
864 /* remove the object header */
865 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
869 g_assert_not_reached ();
878 * mono_class_insecure_overlapping:
879 * check if a class with explicit layout has references and non-references
880 * fields overlapping.
882 * Returns: TRUE if it is insecure to load the type.
885 mono_class_insecure_overlapping (MonoClass *klass)
889 gsize default_bitmap [4] = {0};
891 gsize default_nrbitmap [4] = {0};
892 int i, insecure = FALSE;
895 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
896 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
898 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
899 int idx = i % (sizeof (bitmap [0]) * 8);
900 if (bitmap [idx] & nrbitmap [idx]) {
905 if (bitmap != default_bitmap)
907 if (nrbitmap != default_nrbitmap)
910 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
918 mono_string_alloc (int length)
920 return mono_string_new_size (mono_domain_get (), length);
924 mono_class_compute_gc_descriptor (MonoClass *class)
928 gsize default_bitmap [4] = {0};
929 static gboolean gcj_inited = FALSE;
934 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
935 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
936 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
937 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
939 #ifdef HAVE_GC_GCJ_MALLOC
941 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
945 #ifdef GC_REDIRECT_TO_LOCAL
946 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
947 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
949 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
950 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
955 mono_loader_unlock ();
959 mono_class_init (class);
961 if (class->gc_descr_inited)
964 class->gc_descr_inited = TRUE;
965 class->gc_descr = GC_NO_DESCRIPTOR;
967 bitmap = default_bitmap;
968 if (class == mono_defaults.string_class) {
969 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
970 } else if (class->rank) {
971 mono_class_compute_gc_descriptor (class->element_class);
972 if (!class->element_class->valuetype) {
974 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
975 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
976 class->name_space, class->name);*/
978 /* remove the object header */
979 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
980 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
981 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
982 class->name_space, class->name);*/
983 if (bitmap != default_bitmap)
987 /*static int count = 0;
990 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
991 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
993 if (class->gc_descr == GC_NO_DESCRIPTOR)
994 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
996 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
997 if (bitmap != default_bitmap)
1003 * field_is_special_static:
1004 * @fklass: The MonoClass to look up.
1005 * @field: The MonoClassField describing the field.
1007 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1008 * SPECIAL_STATIC_NONE otherwise.
1011 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1013 MonoCustomAttrInfo *ainfo;
1015 ainfo = mono_custom_attrs_from_field (fklass, field);
1018 for (i = 0; i < ainfo->num_attrs; ++i) {
1019 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1020 if (klass->image == mono_defaults.corlib) {
1021 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1022 mono_custom_attrs_free (ainfo);
1023 return SPECIAL_STATIC_THREAD;
1025 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1026 mono_custom_attrs_free (ainfo);
1027 return SPECIAL_STATIC_CONTEXT;
1031 mono_custom_attrs_free (ainfo);
1032 return SPECIAL_STATIC_NONE;
1035 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1036 #define mix(a,b,c) { \
1037 a -= c; a ^= rot(c, 4); c += b; \
1038 b -= a; b ^= rot(a, 6); a += c; \
1039 c -= b; c ^= rot(b, 8); b += a; \
1040 a -= c; a ^= rot(c,16); c += b; \
1041 b -= a; b ^= rot(a,19); a += c; \
1042 c -= b; c ^= rot(b, 4); b += a; \
1044 #define final(a,b,c) { \
1045 c ^= b; c -= rot(b,14); \
1046 a ^= c; a -= rot(c,11); \
1047 b ^= a; b -= rot(a,25); \
1048 c ^= b; c -= rot(b,16); \
1049 a ^= c; a -= rot(c,4); \
1050 b ^= a; b -= rot(a,14); \
1051 c ^= b; c -= rot(b,24); \
1055 * mono_method_get_imt_slot:
1057 * The IMT slot is embedded into AOTed code, so this must return the same value
1058 * for the same method across all executions. This means:
1059 * - pointers shouldn't be used as hash values.
1060 * - mono_metadata_str_hash () should be used for hashing strings.
1063 mono_method_get_imt_slot (MonoMethod *method)
1065 MonoMethodSignature *sig;
1067 guint32 *hashes_start, *hashes;
1071 /* This can be used to stress tests the collision code */
1075 * We do this to simplify generic sharing. It will hurt
1076 * performance in cases where a class implements two different
1077 * instantiations of the same generic interface.
1078 * The code in build_imt_slots () depends on this.
1080 if (method->is_inflated)
1081 method = ((MonoMethodInflated*)method)->declaring;
1083 sig = mono_method_signature (method);
1084 hashes_count = sig->param_count + 4;
1085 hashes_start = malloc (hashes_count * sizeof (guint32));
1086 hashes = hashes_start;
1088 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1089 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1090 method->klass->name_space, method->klass->name, method->name);
1093 /* Initialize hashes */
1094 hashes [0] = mono_metadata_str_hash (method->klass->name);
1095 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1096 hashes [2] = mono_metadata_str_hash (method->name);
1097 hashes [3] = mono_metadata_type_hash (sig->ret);
1098 for (i = 0; i < sig->param_count; i++) {
1099 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1102 /* Setup internal state */
1103 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1105 /* Handle most of the hashes */
1106 while (hashes_count > 3) {
1115 /* Handle the last 3 hashes (all the case statements fall through) */
1116 switch (hashes_count) {
1117 case 3 : c += hashes [2];
1118 case 2 : b += hashes [1];
1119 case 1 : a += hashes [0];
1121 case 0: /* nothing left to add */
1125 free (hashes_start);
1126 /* Report the result */
1127 return c % MONO_IMT_SIZE;
1136 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1137 guint32 imt_slot = mono_method_get_imt_slot (method);
1138 MonoImtBuilderEntry *entry;
1140 if (slot_num >= 0 && imt_slot != slot_num) {
1141 /* we build just a single imt slot and this is not it */
1145 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1146 entry->key = method;
1147 entry->value.vtable_slot = vtable_slot;
1148 entry->next = imt_builder [imt_slot];
1149 if (imt_builder [imt_slot] != NULL) {
1150 entry->children = imt_builder [imt_slot]->children + 1;
1151 if (entry->children == 1) {
1152 mono_stats.imt_slots_with_collisions++;
1153 *imt_collisions_bitmap |= (1 << imt_slot);
1156 entry->children = 0;
1157 mono_stats.imt_used_slots++;
1159 imt_builder [imt_slot] = entry;
1162 char *method_name = mono_method_full_name (method, TRUE);
1163 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1164 method, method_name, imt_slot, vtable_slot, entry->children);
1165 g_free (method_name);
1172 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1174 MonoMethod *method = e->key;
1175 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1179 method->klass->name_space,
1180 method->klass->name,
1183 printf (" * %s: NULL\n", message);
1189 compare_imt_builder_entries (const void *p1, const void *p2) {
1190 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1191 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1193 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1197 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1199 int count = end - start;
1200 int chunk_start = out_array->len;
1203 for (i = start; i < end; ++i) {
1204 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1205 item->key = sorted_array [i]->key;
1206 item->value = sorted_array [i]->value;
1207 item->has_target_code = sorted_array [i]->has_target_code;
1208 item->is_equals = TRUE;
1210 item->check_target_idx = out_array->len + 1;
1212 item->check_target_idx = 0;
1213 g_ptr_array_add (out_array, item);
1216 int middle = start + count / 2;
1217 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1219 item->key = sorted_array [middle]->key;
1220 item->is_equals = FALSE;
1221 g_ptr_array_add (out_array, item);
1222 imt_emit_ir (sorted_array, start, middle, out_array);
1223 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1229 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1230 int number_of_entries = entries->children + 1;
1231 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1232 GPtrArray *result = g_ptr_array_new ();
1233 MonoImtBuilderEntry *current_entry;
1236 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1237 sorted_array [i] = current_entry;
1239 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1241 /*for (i = 0; i < number_of_entries; i++) {
1242 print_imt_entry (" sorted array:", sorted_array [i], i);
1245 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1247 free (sorted_array);
1252 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1254 if (imt_builder_entry != NULL) {
1255 if (imt_builder_entry->children == 0 && !fail_tramp) {
1256 /* No collision, return the vtable slot contents */
1257 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1259 /* Collision, build the thunk */
1260 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1263 result = imt_thunk_builder (vtable, domain,
1264 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1265 for (i = 0; i < imt_ir->len; ++i)
1266 g_free (g_ptr_array_index (imt_ir, i));
1267 g_ptr_array_free (imt_ir, TRUE);
1279 static MonoImtBuilderEntry*
1280 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1283 * LOCKING: requires the loader and domain locks.
1287 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1291 guint32 imt_collisions_bitmap = 0;
1292 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1293 int method_count = 0;
1294 gboolean record_method_count_for_max_collisions = FALSE;
1295 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1298 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1300 for (i = 0; i < klass->interface_offsets_count; ++i) {
1301 MonoClass *iface = klass->interfaces_packed [i];
1302 int interface_offset = klass->interface_offsets_packed [i];
1303 int method_slot_in_interface, vt_slot;
1305 if (mono_class_has_variant_generic_params (iface))
1306 has_variant_iface = TRUE;
1308 vt_slot = interface_offset;
1309 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1312 if (slot_num >= 0 && iface->is_inflated) {
1314 * The imt slot of the method is the same as for its declaring method,
1315 * see the comment in mono_method_get_imt_slot (), so we can
1316 * avoid inflating methods which will be discarded by
1317 * add_imt_builder_entry anyway.
1319 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1320 if (mono_method_get_imt_slot (method) != slot_num) {
1325 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1326 if (method->is_generic) {
1327 has_generic_virtual = TRUE;
1332 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1333 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1338 if (extra_interfaces) {
1339 int interface_offset = klass->vtable_size;
1341 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1342 MonoClass* iface = list_item->data;
1343 int method_slot_in_interface;
1344 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1345 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1346 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1348 interface_offset += iface->method.count;
1351 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1352 /* overwrite the imt slot only if we're building all the entries or if
1353 * we're building this specific one
1355 if (slot_num < 0 || i == slot_num) {
1356 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1359 if (imt_builder [i]) {
1360 MonoImtBuilderEntry *entry;
1362 /* Link entries with imt_builder [i] */
1363 for (entry = entries; entry->next; entry = entry->next) {
1365 MonoMethod *method = (MonoMethod*)entry->key;
1366 char *method_name = mono_method_full_name (method, TRUE);
1367 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1368 g_free (method_name);
1371 entry->next = imt_builder [i];
1372 entries->children += imt_builder [i]->children + 1;
1374 imt_builder [i] = entries;
1377 if (has_generic_virtual || has_variant_iface) {
1379 * There might be collisions later when the the thunk is expanded.
1381 imt_collisions_bitmap |= (1 << i);
1384 * The IMT thunk might be called with an instance of one of the
1385 * generic virtual methods, so has to fallback to the IMT trampoline.
1387 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1389 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1392 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1396 if (imt_builder [i] != NULL) {
1397 int methods_in_slot = imt_builder [i]->children + 1;
1398 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1399 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1400 record_method_count_for_max_collisions = TRUE;
1402 method_count += methods_in_slot;
1406 mono_stats.imt_number_of_methods += method_count;
1407 if (record_method_count_for_max_collisions) {
1408 mono_stats.imt_method_count_when_max_collisions = method_count;
1411 for (i = 0; i < MONO_IMT_SIZE; i++) {
1412 MonoImtBuilderEntry* entry = imt_builder [i];
1413 while (entry != NULL) {
1414 MonoImtBuilderEntry* next = entry->next;
1420 /* we OR the bitmap since we may build just a single imt slot at a time */
1421 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1425 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1426 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1430 * mono_vtable_build_imt_slot:
1431 * @vtable: virtual object table struct
1432 * @imt_slot: slot in the IMT table
1434 * Fill the given @imt_slot in the IMT table of @vtable with
1435 * a trampoline or a thunk for the case of collisions.
1436 * This is part of the internal mono API.
1438 * LOCKING: Take the domain lock.
1441 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1443 gpointer *imt = (gpointer*)vtable;
1444 imt -= MONO_IMT_SIZE;
1445 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1447 /* no support for extra interfaces: the proxy objects will need
1448 * to build the complete IMT
1449 * Update and heck needs to ahppen inside the proper domain lock, as all
1450 * the changes made to a MonoVTable.
1452 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1453 mono_domain_lock (vtable->domain);
1454 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1455 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1456 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1457 mono_domain_unlock (vtable->domain);
1458 mono_loader_unlock ();
1463 * The first two free list entries both belong to the wait list: The
1464 * first entry is the pointer to the head of the list and the second
1465 * entry points to the last element. That way appending and removing
1466 * the first element are both O(1) operations.
1468 #ifdef MONO_SMALL_CONFIG
1469 #define NUM_FREE_LISTS 6
1471 #define NUM_FREE_LISTS 12
1473 #define FIRST_FREE_LIST_SIZE 64
1474 #define MAX_WAIT_LENGTH 50
1475 #define THUNK_THRESHOLD 10
1478 * LOCKING: The domain lock must be held.
1481 init_thunk_free_lists (MonoDomain *domain)
1483 if (domain->thunk_free_lists)
1485 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1489 list_index_for_size (int item_size)
1492 int size = FIRST_FREE_LIST_SIZE;
1494 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1503 * mono_method_alloc_generic_virtual_thunk:
1505 * @size: size in bytes
1507 * Allocs size bytes to be used for the code of a generic virtual
1508 * thunk. It's either allocated from the domain's code manager or
1509 * reused from a previously invalidated piece.
1511 * LOCKING: The domain lock must be held.
1514 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1516 static gboolean inited = FALSE;
1517 static int generic_virtual_thunks_size = 0;
1521 MonoThunkFreeList **l;
1523 init_thunk_free_lists (domain);
1525 size += sizeof (guint32);
1526 if (size < sizeof (MonoThunkFreeList))
1527 size = sizeof (MonoThunkFreeList);
1529 i = list_index_for_size (size);
1530 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1531 if ((*l)->size >= size) {
1532 MonoThunkFreeList *item = *l;
1534 return ((guint32*)item) + 1;
1538 /* no suitable item found - search lists of larger sizes */
1539 while (++i < NUM_FREE_LISTS) {
1540 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1543 g_assert (item->size > size);
1544 domain->thunk_free_lists [i] = item->next;
1545 return ((guint32*)item) + 1;
1548 /* still nothing found - allocate it */
1550 mono_counters_register ("Generic virtual thunk bytes",
1551 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1554 generic_virtual_thunks_size += size;
1556 p = mono_domain_code_reserve (domain, size);
1559 mono_domain_lock (domain);
1560 if (!domain->generic_virtual_thunks)
1561 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1562 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1563 mono_domain_unlock (domain);
1569 * LOCKING: The domain lock must be held.
1572 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1575 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1576 gboolean found = FALSE;
1578 mono_domain_lock (domain);
1579 if (!domain->generic_virtual_thunks)
1580 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1581 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1583 mono_domain_unlock (domain);
1586 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1588 init_thunk_free_lists (domain);
1590 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1591 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1592 int length = item->length;
1595 /* unlink the first item from the wait list */
1596 domain->thunk_free_lists [0] = item->next;
1597 domain->thunk_free_lists [0]->length = length - 1;
1599 i = list_index_for_size (item->size);
1601 /* put it in the free list */
1602 item->next = domain->thunk_free_lists [i];
1603 domain->thunk_free_lists [i] = item;
1607 if (domain->thunk_free_lists [1]) {
1608 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1609 domain->thunk_free_lists [0]->length++;
1611 g_assert (!domain->thunk_free_lists [0]);
1613 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1614 domain->thunk_free_lists [0]->length = 1;
1618 typedef struct _GenericVirtualCase {
1622 struct _GenericVirtualCase *next;
1623 } GenericVirtualCase;
1626 * get_generic_virtual_entries:
1628 * Return IMT entries for the generic virtual method instances and
1629 * variant interface methods for vtable slot
1632 static MonoImtBuilderEntry*
1633 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1635 GenericVirtualCase *list;
1636 MonoImtBuilderEntry *entries;
1638 mono_domain_lock (domain);
1639 if (!domain->generic_virtual_cases)
1640 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1642 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1645 for (; list; list = list->next) {
1646 MonoImtBuilderEntry *entry;
1648 if (list->count < THUNK_THRESHOLD)
1651 entry = g_new0 (MonoImtBuilderEntry, 1);
1652 entry->key = list->method;
1653 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1654 entry->has_target_code = 1;
1656 entry->children = entries->children + 1;
1657 entry->next = entries;
1661 mono_domain_unlock (domain);
1663 /* FIXME: Leaking memory ? */
1668 * mono_method_add_generic_virtual_invocation:
1670 * @vtable_slot: pointer to the vtable slot
1671 * @method: the inflated generic virtual method
1672 * @code: the method's code
1674 * Registers a call via unmanaged code to a generic virtual method
1675 * instantiation or variant interface method. If the number of calls reaches a threshold
1676 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1677 * virtual method thunk.
1680 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1681 gpointer *vtable_slot,
1682 MonoMethod *method, gpointer code)
1684 static gboolean inited = FALSE;
1685 static int num_added = 0;
1687 GenericVirtualCase *gvc, *list;
1688 MonoImtBuilderEntry *entries;
1692 mono_domain_lock (domain);
1693 if (!domain->generic_virtual_cases)
1694 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1696 /* Check whether the case was already added */
1697 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1700 if (gvc->method == method)
1705 /* If not found, make a new one */
1707 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1708 gvc->method = method;
1711 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1713 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1716 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1722 if (++gvc->count == THUNK_THRESHOLD) {
1723 gpointer *old_thunk = *vtable_slot;
1724 gpointer vtable_trampoline = NULL;
1725 gpointer imt_trampoline = NULL;
1727 if ((gpointer)vtable_slot < (gpointer)vtable) {
1728 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1729 int imt_slot = MONO_IMT_SIZE + displacement;
1731 /* Force the rebuild of the thunk at the next call */
1732 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1733 *vtable_slot = imt_trampoline;
1735 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1737 entries = get_generic_virtual_entries (domain, vtable_slot);
1739 sorted = imt_sort_slot_entries (entries);
1741 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1745 MonoImtBuilderEntry *next = entries->next;
1750 for (i = 0; i < sorted->len; ++i)
1751 g_free (g_ptr_array_index (sorted, i));
1752 g_ptr_array_free (sorted, TRUE);
1755 #ifndef __native_client__
1756 /* We don't re-use any thunks as there is a lot of overhead */
1757 /* to deleting and re-using code in Native Client. */
1758 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1759 invalidate_generic_virtual_thunk (domain, old_thunk);
1763 mono_domain_unlock (domain);
1766 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1769 * mono_class_vtable:
1770 * @domain: the application domain
1771 * @class: the class to initialize
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1775 * On failure, NULL is returned, and class->exception_type is set.
1778 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1780 return mono_class_vtable_full (domain, class, FALSE);
1784 * mono_class_vtable_full:
1785 * @domain: the application domain
1786 * @class: the class to initialize
1787 * @raise_on_error if an exception should be raised on failure or not
1789 * VTables are domain specific because we create domain specific code, and
1790 * they contain the domain specific static class data.
1793 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1795 MonoClassRuntimeInfo *runtime_info;
1799 if (class->exception_type) {
1801 mono_raise_exception (mono_class_get_exception_for_failure (class));
1805 /* this check can be inlined in jitted code, too */
1806 runtime_info = class->runtime_info;
1807 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1808 return runtime_info->domain_vtables [domain->domain_id];
1809 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1813 * mono_class_try_get_vtable:
1814 * @domain: the application domain
1815 * @class: the class to initialize
1817 * This function tries to get the associated vtable from @class if
1818 * it was already created.
1821 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1823 MonoClassRuntimeInfo *runtime_info;
1827 runtime_info = class->runtime_info;
1828 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1829 return runtime_info->domain_vtables [domain->domain_id];
1834 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1837 MonoClassRuntimeInfo *runtime_info, *old_info;
1838 MonoClassField *field;
1840 int i, vtable_slots;
1841 int imt_table_bytes = 0;
1843 guint32 vtable_size, class_size;
1846 gpointer *interface_offsets;
1848 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1849 mono_domain_lock (domain);
1850 runtime_info = class->runtime_info;
1851 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1852 mono_domain_unlock (domain);
1853 mono_loader_unlock ();
1854 return runtime_info->domain_vtables [domain->domain_id];
1856 if (!class->inited || class->exception_type) {
1857 if (!mono_class_init (class) || class->exception_type) {
1858 mono_domain_unlock (domain);
1859 mono_loader_unlock ();
1861 mono_raise_exception (mono_class_get_exception_for_failure (class));
1866 /* Array types require that their element type be valid*/
1867 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1868 MonoClass *element_class = class->element_class;
1869 if (!element_class->inited)
1870 mono_class_init (element_class);
1872 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1873 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1874 mono_class_setup_vtable (element_class);
1876 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1877 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1878 if (class->exception_type == MONO_EXCEPTION_NONE)
1879 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1883 mono_raise_exception (mono_class_get_exception_for_failure (class));
1889 * For some classes, mono_class_init () already computed class->vtable_size, and
1890 * that is all that is needed because of the vtable trampolines.
1892 if (!class->vtable_size)
1893 mono_class_setup_vtable (class);
1895 if (class->generic_class && !class->vtable)
1896 mono_class_check_vtable_constraints (class, NULL);
1898 /* Initialize klass->has_finalize */
1899 mono_class_has_finalizer (class);
1901 if (class->exception_type) {
1902 mono_domain_unlock (domain);
1903 mono_loader_unlock ();
1905 mono_raise_exception (mono_class_get_exception_for_failure (class));
1909 vtable_slots = class->vtable_size;
1910 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1911 class_size = mono_class_data_size (class);
1916 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1917 if (class->interface_offsets_count) {
1918 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1919 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1920 mono_stats.imt_number_of_tables++;
1921 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1924 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1925 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1928 mono_stats.used_class_count++;
1929 mono_stats.class_vtable_size += vtable_size;
1930 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1933 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1935 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1937 vt->rank = class->rank;
1938 vt->domain = domain;
1940 mono_class_compute_gc_descriptor (class);
1942 * We can't use typed allocation in the non-root domains, since the
1943 * collector needs the GC descriptor stored in the vtable even after
1944 * the mempool containing the vtable is destroyed when the domain is
1945 * unloaded. An alternative might be to allocate vtables in the GC
1946 * heap, but this does not seem to work (it leads to crashes inside
1947 * libgc). If that approach is tried, two gc descriptors need to be
1948 * allocated for each class: one for the root domain, and one for all
1949 * other domains. The second descriptor should contain a bit for the
1950 * vtable field in MonoObject, since we can no longer assume the
1951 * vtable is reachable by other roots after the appdomain is unloaded.
1953 #ifdef HAVE_BOEHM_GC
1954 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1955 vt->gc_descr = GC_NO_DESCRIPTOR;
1958 vt->gc_descr = class->gc_descr;
1960 gc_bits = mono_gc_get_vtable_bits (class);
1961 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1963 vt->gc_bits = gc_bits;
1966 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1967 if (class->has_static_refs) {
1968 gpointer statics_gc_descr;
1970 gsize default_bitmap [4] = {0};
1973 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1974 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1975 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1976 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1977 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1978 if (bitmap != default_bitmap)
1981 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1983 vt->has_static_fields = TRUE;
1984 mono_stats.class_static_data_size += class_size;
1989 while ((field = mono_class_get_fields (class, &iter))) {
1990 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1992 if (mono_field_is_deleted (field))
1994 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1995 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1996 if (special_static != SPECIAL_STATIC_NONE) {
1997 guint32 size, offset;
1999 gsize default_bitmap [4] = {0};
2004 if (mono_type_is_reference (field->type)) {
2005 default_bitmap [0] = 1;
2007 bitmap = default_bitmap;
2008 } else if (mono_type_is_struct (field->type)) {
2009 fclass = mono_class_from_mono_type (field->type);
2010 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2011 numbits = max_set + 1;
2013 default_bitmap [0] = 0;
2015 bitmap = default_bitmap;
2017 size = mono_type_size (field->type, &align);
2018 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2019 if (!domain->special_static_fields)
2020 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2021 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2022 if (bitmap != default_bitmap)
2025 * This marks the field as special static to speed up the
2026 * checks in mono_field_static_get/set_value ().
2032 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2033 MonoClass *fklass = mono_class_from_mono_type (field->type);
2034 const char *data = mono_field_get_data (field);
2036 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2037 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2038 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2041 if (fklass->valuetype) {
2042 memcpy (t, data, mono_class_value_size (fklass, NULL));
2044 /* it's a pointer type: add check */
2045 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2052 vt->max_interface_id = class->max_interface_id;
2053 vt->interface_bitmap = class->interface_bitmap;
2055 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2056 // class->name, class->interface_offsets_count);
2058 if (! ARCH_USE_IMT) {
2059 /* initialize interface offsets */
2060 for (i = 0; i < class->interface_offsets_count; ++i) {
2061 int interface_id = class->interfaces_packed [i]->interface_id;
2062 int slot = class->interface_offsets_packed [i];
2063 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2067 /* Initialize vtable */
2068 if (callbacks.get_vtable_trampoline) {
2069 // This also covers the AOT case
2070 for (i = 0; i < class->vtable_size; ++i) {
2071 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2074 mono_class_setup_vtable (class);
2076 for (i = 0; i < class->vtable_size; ++i) {
2079 if ((cm = class->vtable [i]))
2080 vt->vtable [i] = arch_create_jit_trampoline (cm);
2084 if (ARCH_USE_IMT && imt_table_bytes) {
2085 /* Now that the vtable is full, we can actually fill up the IMT */
2086 if (callbacks.get_imt_trampoline) {
2087 /* lazy construction of the IMT entries enabled */
2088 for (i = 0; i < MONO_IMT_SIZE; ++i)
2089 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2091 build_imt (class, vt, domain, interface_offsets, NULL);
2096 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2097 * re-acquire them and check if another thread has created the vtable in the meantime.
2099 /* Special case System.MonoType to avoid infinite recursion */
2100 if (class != mono_defaults.monotype_class) {
2101 /*FIXME check for OOM*/
2102 vt->type = mono_type_get_object (domain, &class->byval_arg);
2103 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2104 /* This is unregistered in
2105 unregister_vtable_reflection_type() in
2107 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2110 if (class->contextbound)
2115 /* class_vtable_array keeps an array of created vtables
2117 g_ptr_array_add (domain->class_vtable_array, vt);
2118 /* class->runtime_info is protected by the loader lock, both when
2119 * it it enlarged and when it is stored info.
2123 * Store the vtable in class->runtime_info.
2124 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2126 mono_memory_barrier ();
2128 old_info = class->runtime_info;
2129 if (old_info && old_info->max_domain >= domain->domain_id) {
2130 /* someone already created a large enough runtime info */
2131 old_info->domain_vtables [domain->domain_id] = vt;
2133 int new_size = domain->domain_id;
2135 new_size = MAX (new_size, old_info->max_domain);
2137 /* make the new size a power of two */
2139 while (new_size > i)
2142 /* this is a bounded memory retention issue: may want to
2143 * handle it differently when we'll have a rcu-like system.
2145 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2146 runtime_info->max_domain = new_size - 1;
2147 /* copy the stuff from the older info */
2149 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2151 runtime_info->domain_vtables [domain->domain_id] = vt;
2153 mono_memory_barrier ();
2154 class->runtime_info = runtime_info;
2157 if (class == mono_defaults.monotype_class) {
2158 /*FIXME check for OOM*/
2159 vt->type = mono_type_get_object (domain, &class->byval_arg);
2160 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2161 /* This is unregistered in
2162 unregister_vtable_reflection_type() in
2164 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2167 mono_domain_unlock (domain);
2168 mono_loader_unlock ();
2170 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2171 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2172 mono_raise_exception (mono_class_get_exception_for_failure (class));
2174 /* make sure the parent is initialized */
2175 /*FIXME shouldn't this fail the current type?*/
2177 mono_class_vtable_full (domain, class->parent, raise_on_error);
2183 * mono_class_proxy_vtable:
2184 * @domain: the application domain
2185 * @remove_class: the remote class
2187 * Creates a vtable for transparent proxies. It is basically
2188 * a copy of the real vtable of the class wrapped in @remote_class,
2189 * but all function pointers invoke the remoting functions, and
2190 * vtable->klass points to the transparent proxy class, and not to @class.
2193 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2196 MonoVTable *vt, *pvt;
2197 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2199 GSList *extra_interfaces = NULL;
2200 MonoClass *class = remote_class->proxy_class;
2201 gpointer *interface_offsets;
2205 #ifdef COMPRESSED_INTERFACE_BITMAP
2209 vt = mono_class_vtable (domain, class);
2210 g_assert (vt); /*FIXME property handle failure*/
2211 max_interface_id = vt->max_interface_id;
2213 /* Calculate vtable space for extra interfaces */
2214 for (j = 0; j < remote_class->interface_count; j++) {
2215 MonoClass* iclass = remote_class->interfaces[j];
2219 /*FIXME test for interfaces with variant generic arguments*/
2220 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2221 continue; /* interface implemented by the class */
2222 if (g_slist_find (extra_interfaces, iclass))
2225 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2227 method_count = mono_class_num_methods (iclass);
2229 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2230 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2232 for (i = 0; i < ifaces->len; ++i) {
2233 MonoClass *ic = g_ptr_array_index (ifaces, i);
2234 /*FIXME test for interfaces with variant generic arguments*/
2235 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2236 continue; /* interface implemented by the class */
2237 if (g_slist_find (extra_interfaces, ic))
2239 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2240 method_count += mono_class_num_methods (ic);
2242 g_ptr_array_free (ifaces, TRUE);
2245 extra_interface_vtsize += method_count * sizeof (gpointer);
2246 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2250 mono_stats.imt_number_of_tables++;
2251 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2252 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2253 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2255 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2256 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2259 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2261 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2263 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2265 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2266 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2268 pvt->klass = mono_defaults.transparent_proxy_class;
2269 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2270 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2272 /* initialize vtable */
2273 mono_class_setup_vtable (class);
2274 for (i = 0; i < class->vtable_size; ++i) {
2277 if ((cm = class->vtable [i]))
2278 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2280 pvt->vtable [i] = NULL;
2283 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2284 /* create trampolines for abstract methods */
2285 for (k = class; k; k = k->parent) {
2287 gpointer iter = NULL;
2288 while ((m = mono_class_get_methods (k, &iter)))
2289 if (!pvt->vtable [m->slot])
2290 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2294 pvt->max_interface_id = max_interface_id;
2295 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2296 #ifdef COMPRESSED_INTERFACE_BITMAP
2297 bitmap = g_malloc0 (bsize);
2299 bitmap = mono_domain_alloc0 (domain, bsize);
2302 if (! ARCH_USE_IMT) {
2303 /* initialize interface offsets */
2304 for (i = 0; i < class->interface_offsets_count; ++i) {
2305 int interface_id = class->interfaces_packed [i]->interface_id;
2306 int slot = class->interface_offsets_packed [i];
2307 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2310 for (i = 0; i < class->interface_offsets_count; ++i) {
2311 int interface_id = class->interfaces_packed [i]->interface_id;
2312 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2315 if (extra_interfaces) {
2316 int slot = class->vtable_size;
2322 /* Create trampolines for the methods of the interfaces */
2323 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2324 interf = list_item->data;
2326 if (! ARCH_USE_IMT) {
2327 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2329 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2333 while ((cm = mono_class_get_methods (interf, &iter)))
2334 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2336 slot += mono_class_num_methods (interf);
2338 if (! ARCH_USE_IMT) {
2339 g_slist_free (extra_interfaces);
2344 /* Now that the vtable is full, we can actually fill up the IMT */
2345 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2346 if (extra_interfaces) {
2347 g_slist_free (extra_interfaces);
2351 #ifdef COMPRESSED_INTERFACE_BITMAP
2352 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2353 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2354 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2357 pvt->interface_bitmap = bitmap;
2363 * mono_class_field_is_special_static:
2365 * Returns whether @field is a thread/context static field.
2368 mono_class_field_is_special_static (MonoClassField *field)
2370 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2372 if (mono_field_is_deleted (field))
2374 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2375 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2382 * mono_class_field_get_special_static_type:
2383 * @field: The MonoClassField describing the field.
2385 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2386 * SPECIAL_STATIC_NONE otherwise.
2389 mono_class_field_get_special_static_type (MonoClassField *field)
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2392 return SPECIAL_STATIC_NONE;
2393 if (mono_field_is_deleted (field))
2394 return SPECIAL_STATIC_NONE;
2395 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2396 return field_is_special_static (field->parent, field);
2397 return SPECIAL_STATIC_NONE;
2401 * mono_class_has_special_static_fields:
2403 * Returns whenever @klass has any thread/context static fields.
2406 mono_class_has_special_static_fields (MonoClass *klass)
2408 MonoClassField *field;
2412 while ((field = mono_class_get_fields (klass, &iter))) {
2413 g_assert (field->parent == klass);
2414 if (mono_class_field_is_special_static (field))
2422 * create_remote_class_key:
2423 * Creates an array of pointers that can be used as a hash key for a remote class.
2424 * The first element of the array is the number of pointers.
2427 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2432 if (remote_class == NULL) {
2433 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2434 key = g_malloc (sizeof(gpointer) * 3);
2435 key [0] = GINT_TO_POINTER (2);
2436 key [1] = mono_defaults.marshalbyrefobject_class;
2437 key [2] = extra_class;
2439 key = g_malloc (sizeof(gpointer) * 2);
2440 key [0] = GINT_TO_POINTER (1);
2441 key [1] = extra_class;
2444 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2445 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2446 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2447 key [1] = remote_class->proxy_class;
2449 // Keep the list of interfaces sorted
2450 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2451 if (extra_class && remote_class->interfaces [i] > extra_class) {
2452 key [j++] = extra_class;
2455 key [j] = remote_class->interfaces [i];
2458 key [j] = extra_class;
2460 // Replace the old class. The interface list is the same
2461 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2463 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2464 for (i = 0; i < remote_class->interface_count; i++)
2465 key [2 + i] = remote_class->interfaces [i];
2473 * copy_remote_class_key:
2475 * Make a copy of KEY in the domain and return the copy.
2478 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2480 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2481 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2483 memcpy (mp_key, key, key_size);
2489 * mono_remote_class:
2490 * @domain: the application domain
2491 * @class_name: name of the remote class
2493 * Creates and initializes a MonoRemoteClass object for a remote type.
2495 * Can raise an exception on failure.
2498 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2501 MonoRemoteClass *rc;
2502 gpointer* key, *mp_key;
2505 key = create_remote_class_key (NULL, proxy_class);
2507 mono_domain_lock (domain);
2508 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2512 mono_domain_unlock (domain);
2516 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2517 if (!mono_error_ok (&error)) {
2519 mono_domain_unlock (domain);
2520 mono_error_raise_exception (&error);
2523 mp_key = copy_remote_class_key (domain, key);
2527 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2528 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2529 rc->interface_count = 1;
2530 rc->interfaces [0] = proxy_class;
2531 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2533 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2534 rc->interface_count = 0;
2535 rc->proxy_class = proxy_class;
2538 rc->default_vtable = NULL;
2539 rc->xdomain_vtable = NULL;
2540 rc->proxy_class_name = name;
2541 #ifndef DISABLE_PERFCOUNTERS
2542 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2545 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2547 mono_domain_unlock (domain);
2552 * clone_remote_class:
2553 * Creates a copy of the remote_class, adding the provided class or interface
2555 static MonoRemoteClass*
2556 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2558 MonoRemoteClass *rc;
2559 gpointer* key, *mp_key;
2561 key = create_remote_class_key (remote_class, extra_class);
2562 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2568 mp_key = copy_remote_class_key (domain, key);
2572 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2574 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2575 rc->proxy_class = remote_class->proxy_class;
2576 rc->interface_count = remote_class->interface_count + 1;
2578 // Keep the list of interfaces sorted, since the hash key of
2579 // the remote class depends on this
2580 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2581 if (remote_class->interfaces [i] > extra_class && i == j)
2582 rc->interfaces [j++] = extra_class;
2583 rc->interfaces [j] = remote_class->interfaces [i];
2586 rc->interfaces [j] = extra_class;
2588 // Replace the old class. The interface array is the same
2589 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2590 rc->proxy_class = extra_class;
2591 rc->interface_count = remote_class->interface_count;
2592 if (rc->interface_count > 0)
2593 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2596 rc->default_vtable = NULL;
2597 rc->xdomain_vtable = NULL;
2598 rc->proxy_class_name = remote_class->proxy_class_name;
2600 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2606 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2608 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2609 mono_domain_lock (domain);
2610 if (rp->target_domain_id != -1) {
2611 if (remote_class->xdomain_vtable == NULL)
2612 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2613 mono_domain_unlock (domain);
2614 mono_loader_unlock ();
2615 return remote_class->xdomain_vtable;
2617 if (remote_class->default_vtable == NULL) {
2620 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2621 klass = mono_class_from_mono_type (type);
2623 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2624 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2627 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2630 mono_domain_unlock (domain);
2631 mono_loader_unlock ();
2632 return remote_class->default_vtable;
2636 * mono_upgrade_remote_class:
2637 * @domain: the application domain
2638 * @tproxy: the proxy whose remote class has to be upgraded.
2639 * @klass: class to which the remote class can be casted.
2641 * Updates the vtable of the remote class by adding the necessary method slots
2642 * and interface offsets so it can be safely casted to klass. klass can be a
2643 * class or an interface.
2646 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2648 MonoTransparentProxy *tproxy;
2649 MonoRemoteClass *remote_class;
2650 gboolean redo_vtable;
2652 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2653 mono_domain_lock (domain);
2655 tproxy = (MonoTransparentProxy*) proxy_object;
2656 remote_class = tproxy->remote_class;
2658 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2661 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2662 if (remote_class->interfaces [i] == klass)
2663 redo_vtable = FALSE;
2666 redo_vtable = (remote_class->proxy_class != klass);
2670 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2671 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2674 mono_domain_unlock (domain);
2675 mono_loader_unlock ();
2680 * mono_object_get_virtual_method:
2681 * @obj: object to operate on.
2684 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2685 * the instance of a callvirt of method.
2688 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2691 MonoMethod **vtable;
2693 MonoMethod *res = NULL;
2695 klass = mono_object_class (obj);
2696 if (klass == mono_defaults.transparent_proxy_class) {
2697 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2703 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2706 mono_class_setup_vtable (klass);
2707 vtable = klass->vtable;
2709 if (method->slot == -1) {
2710 /* method->slot might not be set for instances of generic methods */
2711 if (method->is_inflated) {
2712 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2713 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2716 g_assert_not_reached ();
2720 /* check method->slot is a valid index: perform isinstance? */
2721 if (method->slot != -1) {
2722 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2724 gboolean variance_used = FALSE;
2725 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2726 g_assert (iface_offset > 0);
2727 res = vtable [iface_offset + method->slot];
2730 res = vtable [method->slot];
2735 /* It may be an interface, abstract class method or generic method */
2736 if (!res || mono_method_signature (res)->generic_param_count)
2739 /* generic methods demand invoke_with_check */
2740 if (mono_method_signature (res)->generic_param_count)
2741 res = mono_marshal_get_remoting_invoke_with_check (res);
2744 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2745 res = mono_cominterop_get_invoke (res);
2748 res = mono_marshal_get_remoting_invoke (res);
2751 if (method->is_inflated) {
2752 /* Have to inflate the result */
2753 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2763 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2765 g_error ("runtime invoke called on uninitialized runtime");
2769 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2772 * mono_runtime_invoke:
2773 * @method: method to invoke
2774 * @obJ: object instance
2775 * @params: arguments to the method
2776 * @exc: exception information.
2778 * Invokes the method represented by @method on the object @obj.
2780 * obj is the 'this' pointer, it should be NULL for static
2781 * methods, a MonoObject* for object instances and a pointer to
2782 * the value type for value types.
2784 * The params array contains the arguments to the method with the
2785 * same convention: MonoObject* pointers for object instances and
2786 * pointers to the value type otherwise.
2788 * From unmanaged code you'll usually use the
2789 * mono_runtime_invoke() variant.
2791 * Note that this function doesn't handle virtual methods for
2792 * you, it will exec the exact method you pass: we still need to
2793 * expose a function to lookup the derived class implementation
2794 * of a virtual method (there are examples of this in the code,
2797 * You can pass NULL as the exc argument if you don't want to
2798 * catch exceptions, otherwise, *exc will be set to the exception
2799 * thrown, if any. if an exception is thrown, you can't use the
2800 * MonoObject* result from the function.
2802 * If the method returns a value type, it is boxed in an object
2806 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2810 if (mono_runtime_get_no_exec ())
2811 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2813 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2814 mono_profiler_method_start_invoke (method);
2816 result = default_mono_runtime_invoke (method, obj, params, exc);
2818 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2819 mono_profiler_method_end_invoke (method);
2825 * mono_method_get_unmanaged_thunk:
2826 * @method: method to generate a thunk for.
2828 * Returns an unmanaged->managed thunk that can be used to call
2829 * a managed method directly from C.
2831 * The thunk's C signature closely matches the managed signature:
2833 * C#: public bool Equals (object obj);
2834 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2835 * MonoObject*, MonoException**);
2837 * The 1st ("this") parameter must not be used with static methods:
2839 * C#: public static bool ReferenceEquals (object a, object b);
2840 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2843 * The last argument must be a non-null pointer of a MonoException* pointer.
2844 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2845 * exception has been thrown in managed code. Otherwise it will point
2846 * to the MonoException* caught by the thunk. In this case, the result of
2847 * the thunk is undefined:
2849 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2850 * MonoException *ex = NULL;
2851 * Equals func = mono_method_get_unmanaged_thunk (method);
2852 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2854 * // handle exception
2857 * The calling convention of the thunk matches the platform's default
2858 * convention. This means that under Windows, C declarations must
2859 * contain the __stdcall attribute:
2861 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2862 * MonoObject*, MonoException**);
2866 * Value type arguments and return values are treated as they were objects:
2868 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2869 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2871 * Arguments must be properly boxed upon trunk's invocation, while return
2872 * values must be unboxed.
2875 mono_method_get_unmanaged_thunk (MonoMethod *method)
2877 method = mono_marshal_get_thunk_invoke_wrapper (method);
2878 return mono_compile_method (method);
2882 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2886 /* object fields cannot be byref, so we don't need a
2888 gpointer *p = (gpointer*)dest;
2895 case MONO_TYPE_BOOLEAN:
2897 case MONO_TYPE_U1: {
2898 guint8 *p = (guint8*)dest;
2899 *p = value ? *(guint8*)value : 0;
2904 case MONO_TYPE_CHAR: {
2905 guint16 *p = (guint16*)dest;
2906 *p = value ? *(guint16*)value : 0;
2909 #if SIZEOF_VOID_P == 4
2914 case MONO_TYPE_U4: {
2915 gint32 *p = (gint32*)dest;
2916 *p = value ? *(gint32*)value : 0;
2919 #if SIZEOF_VOID_P == 8
2924 case MONO_TYPE_U8: {
2925 gint64 *p = (gint64*)dest;
2926 *p = value ? *(gint64*)value : 0;
2929 case MONO_TYPE_R4: {
2930 float *p = (float*)dest;
2931 *p = value ? *(float*)value : 0;
2934 case MONO_TYPE_R8: {
2935 double *p = (double*)dest;
2936 *p = value ? *(double*)value : 0;
2939 case MONO_TYPE_STRING:
2940 case MONO_TYPE_SZARRAY:
2941 case MONO_TYPE_CLASS:
2942 case MONO_TYPE_OBJECT:
2943 case MONO_TYPE_ARRAY:
2944 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2946 case MONO_TYPE_FNPTR:
2947 case MONO_TYPE_PTR: {
2948 gpointer *p = (gpointer*)dest;
2949 *p = deref_pointer? *(gpointer*)value: value;
2952 case MONO_TYPE_VALUETYPE:
2953 /* note that 't' and 'type->type' can be different */
2954 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2955 t = mono_class_enum_basetype (type->data.klass)->type;
2958 MonoClass *class = mono_class_from_mono_type (type);
2959 int size = mono_class_value_size (class, NULL);
2961 mono_gc_bzero (dest, size);
2963 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2966 case MONO_TYPE_GENERICINST:
2967 t = type->data.generic_class->container_class->byval_arg.type;
2970 g_error ("got type %x", type->type);
2975 * mono_field_set_value:
2976 * @obj: Instance object
2977 * @field: MonoClassField describing the field to set
2978 * @value: The value to be set
2980 * Sets the value of the field described by @field in the object instance @obj
2981 * to the value passed in @value. This method should only be used for instance
2982 * fields. For static fields, use mono_field_static_set_value.
2984 * The value must be on the native format of the field type.
2987 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2991 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2993 dest = (char*)obj + field->offset;
2994 set_value (field->type, dest, value, FALSE);
2998 * mono_field_static_set_value:
2999 * @field: MonoClassField describing the field to set
3000 * @value: The value to be set
3002 * Sets the value of the static field described by @field
3003 * to the value passed in @value.
3005 * The value must be on the native format of the field type.
3008 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3012 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3013 /* you cant set a constant! */
3014 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3016 if (field->offset == -1) {
3017 /* Special static */
3020 mono_domain_lock (vt->domain);
3021 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3022 mono_domain_unlock (vt->domain);
3023 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3025 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3027 set_value (field->type, dest, value, FALSE);
3031 * mono_vtable_get_static_field_data:
3033 * Internal use function: return a pointer to the memory holding the static fields
3034 * for a class or NULL if there are no static fields.
3035 * This is exported only for use by the debugger.
3038 mono_vtable_get_static_field_data (MonoVTable *vt)
3040 if (!vt->has_static_fields)
3042 return vt->vtable [vt->klass->vtable_size];
3046 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3050 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3051 if (field->offset == -1) {
3052 /* Special static */
3055 mono_domain_lock (vt->domain);
3056 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3057 mono_domain_unlock (vt->domain);
3058 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3060 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3063 src = (guint8*)obj + field->offset;
3070 * mono_field_get_value:
3071 * @obj: Object instance
3072 * @field: MonoClassField describing the field to fetch information from
3073 * @value: pointer to the location where the value will be stored
3075 * Use this routine to get the value of the field @field in the object
3078 * The pointer provided by value must be of the field type, for reference
3079 * types this is a MonoObject*, for value types its the actual pointer to
3084 * mono_field_get_value (obj, int_field, &i);
3087 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3093 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3095 src = (char*)obj + field->offset;
3096 set_value (field->type, value, src, TRUE);
3100 * mono_field_get_value_object:
3101 * @domain: domain where the object will be created (if boxing)
3102 * @field: MonoClassField describing the field to fetch information from
3103 * @obj: The object instance for the field.
3105 * Returns: a new MonoObject with the value from the given field. If the
3106 * field represents a value type, the value is boxed.
3110 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3114 MonoVTable *vtable = NULL;
3116 gboolean is_static = FALSE;
3117 gboolean is_ref = FALSE;
3118 gboolean is_literal = FALSE;
3119 gboolean is_ptr = FALSE;
3121 MonoType *type = mono_field_get_type_checked (field, &error);
3123 if (!mono_error_ok (&error))
3124 mono_error_raise_exception (&error);
3126 switch (type->type) {
3127 case MONO_TYPE_STRING:
3128 case MONO_TYPE_OBJECT:
3129 case MONO_TYPE_CLASS:
3130 case MONO_TYPE_ARRAY:
3131 case MONO_TYPE_SZARRAY:
3136 case MONO_TYPE_BOOLEAN:
3139 case MONO_TYPE_CHAR:
3148 case MONO_TYPE_VALUETYPE:
3149 is_ref = type->byref;
3151 case MONO_TYPE_GENERICINST:
3152 is_ref = !mono_type_generic_inst_is_valuetype (type);
3158 g_error ("type 0x%x not handled in "
3159 "mono_field_get_value_object", type->type);
3163 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3166 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3170 vtable = mono_class_vtable (domain, field->parent);
3172 char *name = mono_type_get_full_name (field->parent);
3173 /*FIXME extend this to use the MonoError api*/
3174 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3178 if (!vtable->initialized)
3179 mono_runtime_class_init (vtable);
3187 get_default_field_value (domain, field, &o);
3188 } else if (is_static) {
3189 mono_field_static_get_value (vtable, field, &o);
3191 mono_field_get_value (obj, field, &o);
3197 static MonoMethod *m;
3203 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3204 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3210 get_default_field_value (domain, field, v);
3211 } else if (is_static) {
3212 mono_field_static_get_value (vtable, field, v);
3214 mono_field_get_value (obj, field, v);
3217 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3219 args [1] = mono_type_get_object (mono_domain_get (), type);
3221 return mono_runtime_invoke (m, NULL, args, NULL);
3224 /* boxed value type */
3225 klass = mono_class_from_mono_type (type);
3227 if (mono_class_is_nullable (klass))
3228 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3230 o = mono_object_new (domain, klass);
3231 v = ((gchar *) o) + sizeof (MonoObject);
3234 get_default_field_value (domain, field, v);
3235 } else if (is_static) {
3236 mono_field_static_get_value (vtable, field, v);
3238 mono_field_get_value (obj, field, v);
3245 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3248 const char *p = blob;
3249 mono_metadata_decode_blob_size (p, &p);
3252 case MONO_TYPE_BOOLEAN:
3255 *(guint8 *) value = *p;
3257 case MONO_TYPE_CHAR:
3260 *(guint16*) value = read16 (p);
3264 *(guint32*) value = read32 (p);
3268 *(guint64*) value = read64 (p);
3271 readr4 (p, (float*) value);
3274 readr8 (p, (double*) value);
3276 case MONO_TYPE_STRING:
3277 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3279 case MONO_TYPE_CLASS:
3280 *(gpointer*) value = NULL;
3284 g_warning ("type 0x%02x should not be in constant table", type);
3290 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3292 MonoTypeEnum def_type;
3295 data = mono_class_get_field_default_value (field, &def_type);
3296 mono_get_constant_value_from_blob (domain, def_type, data, value);
3300 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3304 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3306 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3307 get_default_field_value (vt->domain, field, value);
3311 if (field->offset == -1) {
3312 /* Special static */
3313 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3314 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3316 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3318 set_value (field->type, value, src, TRUE);
3322 * mono_field_static_get_value:
3323 * @vt: vtable to the object
3324 * @field: MonoClassField describing the field to fetch information from
3325 * @value: where the value is returned
3327 * Use this routine to get the value of the static field @field value.
3329 * The pointer provided by value must be of the field type, for reference
3330 * types this is a MonoObject*, for value types its the actual pointer to
3335 * mono_field_static_get_value (vt, int_field, &i);
3338 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3340 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3344 * mono_property_set_value:
3345 * @prop: MonoProperty to set
3346 * @obj: instance object on which to act
3347 * @params: parameters to pass to the propery
3348 * @exc: optional exception
3350 * Invokes the property's set method with the given arguments on the
3351 * object instance obj (or NULL for static properties).
3353 * You can pass NULL as the exc argument if you don't want to
3354 * catch exceptions, otherwise, *exc will be set to the exception
3355 * thrown, if any. if an exception is thrown, you can't use the
3356 * MonoObject* result from the function.
3359 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3361 default_mono_runtime_invoke (prop->set, obj, params, exc);
3365 * mono_property_get_value:
3366 * @prop: MonoProperty to fetch
3367 * @obj: instance object on which to act
3368 * @params: parameters to pass to the propery
3369 * @exc: optional exception
3371 * Invokes the property's get method with the given arguments on the
3372 * object instance obj (or NULL for static properties).
3374 * You can pass NULL as the exc argument if you don't want to
3375 * catch exceptions, otherwise, *exc will be set to the exception
3376 * thrown, if any. if an exception is thrown, you can't use the
3377 * MonoObject* result from the function.
3379 * Returns: the value from invoking the get method on the property.
3382 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3384 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3388 * mono_nullable_init:
3389 * @buf: The nullable structure to initialize.
3390 * @value: the value to initialize from
3391 * @klass: the type for the object
3393 * Initialize the nullable structure pointed to by @buf from @value which
3394 * should be a boxed value type. The size of @buf should be able to hold
3395 * as much data as the @klass->instance_size (which is the number of bytes
3396 * that will be copies).
3398 * Since Nullables have variable structure, we can not define a C
3399 * structure for them.
3402 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3404 MonoClass *param_class = klass->cast_class;
3406 mono_class_setup_fields_locking (klass);
3407 g_assert (klass->fields_inited);
3409 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3410 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3412 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3414 if (param_class->has_references)
3415 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3417 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3419 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3424 * mono_nullable_box:
3425 * @buf: The buffer representing the data to be boxed
3426 * @klass: the type to box it as.
3428 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3432 mono_nullable_box (guint8 *buf, MonoClass *klass)
3434 MonoClass *param_class = klass->cast_class;
3436 mono_class_setup_fields_locking (klass);
3437 g_assert (klass->fields_inited);
3439 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3440 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3442 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3443 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3444 if (param_class->has_references)
3445 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3447 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3455 * mono_get_delegate_invoke:
3456 * @klass: The delegate class
3458 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3461 mono_get_delegate_invoke (MonoClass *klass)
3465 /* This is called at runtime, so avoid the slower search in metadata */
3466 mono_class_setup_methods (klass);
3467 if (klass->exception_type)
3469 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3474 * mono_runtime_delegate_invoke:
3475 * @delegate: pointer to a delegate object.
3476 * @params: parameters for the delegate.
3477 * @exc: Pointer to the exception result.
3479 * Invokes the delegate method @delegate with the parameters provided.
3481 * You can pass NULL as the exc argument if you don't want to
3482 * catch exceptions, otherwise, *exc will be set to the exception
3483 * thrown, if any. if an exception is thrown, you can't use the
3484 * MonoObject* result from the function.
3487 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3490 MonoClass *klass = delegate->vtable->klass;
3492 im = mono_get_delegate_invoke (klass);
3494 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3496 return mono_runtime_invoke (im, delegate, params, exc);
3499 static char **main_args = NULL;
3500 static int num_main_args;
3503 * mono_runtime_get_main_args:
3505 * Returns: a MonoArray with the arguments passed to the main program
3508 mono_runtime_get_main_args (void)
3512 MonoDomain *domain = mono_domain_get ();
3517 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3519 for (i = 0; i < num_main_args; ++i)
3520 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3526 free_main_args (void)
3530 for (i = 0; i < num_main_args; ++i)
3531 g_free (main_args [i]);
3536 * mono_runtime_run_main:
3537 * @method: the method to start the application with (usually Main)
3538 * @argc: number of arguments from the command line
3539 * @argv: array of strings from the command line
3540 * @exc: excetption results
3542 * Execute a standard Main() method (argc/argv contains the
3543 * executable name). This method also sets the command line argument value
3544 * needed by System.Environment.
3549 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3553 MonoArray *args = NULL;
3554 MonoDomain *domain = mono_domain_get ();
3555 gchar *utf8_fullpath;
3556 MonoMethodSignature *sig;
3558 g_assert (method != NULL);
3560 mono_thread_set_main (mono_thread_current ());
3562 main_args = g_new0 (char*, argc);
3563 num_main_args = argc;
3565 if (!g_path_is_absolute (argv [0])) {
3566 gchar *basename = g_path_get_basename (argv [0]);
3567 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3571 utf8_fullpath = mono_utf8_from_external (fullpath);
3572 if(utf8_fullpath == NULL) {
3573 /* Printing the arg text will cause glib to
3574 * whinge about "Invalid UTF-8", but at least
3575 * its relevant, and shows the problem text
3578 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3579 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3586 utf8_fullpath = mono_utf8_from_external (argv[0]);
3587 if(utf8_fullpath == NULL) {
3588 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3589 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3594 main_args [0] = utf8_fullpath;
3596 for (i = 1; i < argc; ++i) {
3599 utf8_arg=mono_utf8_from_external (argv[i]);
3600 if(utf8_arg==NULL) {
3601 /* Ditto the comment about Invalid UTF-8 here */
3602 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3603 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3607 main_args [i] = utf8_arg;
3612 sig = mono_method_signature (method);
3614 g_print ("Unable to load Main method.\n");
3618 if (sig->param_count) {
3619 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3620 for (i = 0; i < argc; ++i) {
3621 /* The encodings should all work, given that
3622 * we've checked all these args for the
3625 gchar *str = mono_utf8_from_external (argv [i]);
3626 MonoString *arg = mono_string_new (domain, str);
3627 mono_array_setref (args, i, arg);
3631 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3634 mono_assembly_set_main (method->klass->image->assembly);
3636 return mono_runtime_exec_main (method, args, exc);
3640 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3642 static MonoMethod *serialize_method;
3647 if (!serialize_method) {
3648 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3649 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3652 if (!serialize_method) {
3657 g_assert (!mono_object_class (obj)->marshalbyref);
3661 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3669 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3671 static MonoMethod *deserialize_method;
3676 if (!deserialize_method) {
3677 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3678 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3680 if (!deserialize_method) {
3687 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3695 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3697 static MonoMethod *get_proxy_method;
3699 MonoDomain *domain = mono_domain_get ();
3700 MonoRealProxy *real_proxy;
3701 MonoReflectionType *reflection_type;
3702 MonoTransparentProxy *transparent_proxy;
3704 if (!get_proxy_method)
3705 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3707 g_assert (obj->vtable->klass->marshalbyref);
3709 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3710 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3712 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3713 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3716 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3720 return (MonoObject*) transparent_proxy;
3724 * mono_object_xdomain_representation
3726 * @target_domain: a domain
3727 * @exc: pointer to a MonoObject*
3729 * Creates a representation of obj in the domain target_domain. This
3730 * is either a copy of obj arrived through via serialization and
3731 * deserialization or a proxy, depending on whether the object is
3732 * serializable or marshal by ref. obj must not be in target_domain.
3734 * If the object cannot be represented in target_domain, NULL is
3735 * returned and *exc is set to an appropriate exception.
3738 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3740 MonoObject *deserialized = NULL;
3741 gboolean failure = FALSE;
3745 if (mono_object_class (obj)->marshalbyref) {
3746 deserialized = make_transparent_proxy (obj, &failure, exc);
3748 MonoDomain *domain = mono_domain_get ();
3749 MonoObject *serialized;
3751 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3752 serialized = serialize_object (obj, &failure, exc);
3753 mono_domain_set_internal_with_options (target_domain, FALSE);
3755 deserialized = deserialize_object (serialized, &failure, exc);
3756 if (domain != target_domain)
3757 mono_domain_set_internal_with_options (domain, FALSE);
3760 return deserialized;
3763 /* Used in call_unhandled_exception_delegate */
3765 create_unhandled_exception_eventargs (MonoObject *exc)
3769 MonoMethod *method = NULL;
3770 MonoBoolean is_terminating = TRUE;
3773 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3776 mono_class_init (klass);
3778 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3779 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3783 args [1] = &is_terminating;
3785 obj = mono_object_new (mono_domain_get (), klass);
3786 mono_runtime_invoke (method, obj, args, NULL);
3791 /* Used in mono_unhandled_exception */
3793 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3794 MonoObject *e = NULL;
3796 MonoDomain *current_domain = mono_domain_get ();
3798 if (domain != current_domain)
3799 mono_domain_set_internal_with_options (domain, FALSE);
3801 g_assert (domain == mono_object_domain (domain->domain));
3803 if (mono_object_domain (exc) != domain) {
3804 MonoObject *serialization_exc;
3806 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3808 if (serialization_exc) {
3810 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3813 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3814 "System.Runtime.Serialization", "SerializationException",
3815 "Could not serialize unhandled exception.");
3819 g_assert (mono_object_domain (exc) == domain);
3821 pa [0] = domain->domain;
3822 pa [1] = create_unhandled_exception_eventargs (exc);
3823 mono_runtime_delegate_invoke (delegate, pa, &e);
3825 if (domain != current_domain)
3826 mono_domain_set_internal_with_options (current_domain, FALSE);
3830 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3831 if (!mono_error_ok (&error)) {
3832 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3833 mono_error_cleanup (&error);
3835 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3841 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3844 * mono_runtime_unhandled_exception_policy_set:
3845 * @policy: the new policy
3847 * This is a VM internal routine.
3849 * Sets the runtime policy for handling unhandled exceptions.
3852 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3853 runtime_unhandled_exception_policy = policy;
3857 * mono_runtime_unhandled_exception_policy_get:
3859 * This is a VM internal routine.
3861 * Gets the runtime policy for handling unhandled exceptions.
3863 MonoRuntimeUnhandledExceptionPolicy
3864 mono_runtime_unhandled_exception_policy_get (void) {
3865 return runtime_unhandled_exception_policy;
3869 * mono_unhandled_exception:
3870 * @exc: exception thrown
3872 * This is a VM internal routine.
3874 * We call this function when we detect an unhandled exception
3875 * in the default domain.
3877 * It invokes the * UnhandledException event in AppDomain or prints
3878 * a warning to the console
3881 mono_unhandled_exception (MonoObject *exc)
3883 MonoDomain *current_domain = mono_domain_get ();
3884 MonoDomain *root_domain = mono_get_root_domain ();
3885 MonoClassField *field;
3886 MonoObject *current_appdomain_delegate;
3887 MonoObject *root_appdomain_delegate;
3889 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3890 "UnhandledException");
3893 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3894 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3895 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3896 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3897 if (current_domain != root_domain) {
3898 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3900 current_appdomain_delegate = NULL;
3903 /* set exitcode only if we will abort the process */
3904 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3906 mono_environment_exitcode_set (1);
3907 mono_print_unhandled_exception (exc);
3909 if (root_appdomain_delegate) {
3910 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3912 if (current_appdomain_delegate) {
3913 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3920 * mono_runtime_exec_managed_code:
3921 * @domain: Application domain
3922 * @main_func: function to invoke from the execution thread
3923 * @main_args: parameter to the main_func
3925 * Launch a new thread to execute a function
3927 * main_func is called back from the thread with main_args as the
3928 * parameter. The callback function is expected to start Main()
3929 * eventually. This function then waits for all managed threads to
3931 * It is not necesseray anymore to execute managed code in a subthread,
3932 * so this function should not be used anymore by default: just
3933 * execute the code and then call mono_thread_manage ().
3936 mono_runtime_exec_managed_code (MonoDomain *domain,
3937 MonoMainThreadFunc main_func,
3940 mono_thread_create (domain, main_func, main_args);
3942 mono_thread_manage ();
3946 * Execute a standard Main() method (args doesn't contain the
3950 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3955 MonoCustomAttrInfo* cinfo;
3956 gboolean has_stathread_attribute;
3957 MonoInternalThread* thread = mono_thread_internal_current ();
3963 domain = mono_object_domain (args);
3964 if (!domain->entry_assembly) {
3966 MonoAssembly *assembly;
3968 assembly = method->klass->image->assembly;
3969 domain->entry_assembly = assembly;
3970 /* Domains created from another domain already have application_base and configuration_file set */
3971 if (domain->setup->application_base == NULL) {
3972 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3975 if (domain->setup->configuration_file == NULL) {
3976 str = g_strconcat (assembly->image->name, ".config", NULL);
3977 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3979 mono_set_private_bin_path_from_config (domain);
3983 cinfo = mono_custom_attrs_from_method (method);
3985 static MonoClass *stathread_attribute = NULL;
3986 if (!stathread_attribute)
3987 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3988 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3990 mono_custom_attrs_free (cinfo);
3992 has_stathread_attribute = FALSE;
3994 if (has_stathread_attribute) {
3995 thread->apartment_state = ThreadApartmentState_STA;
3997 thread->apartment_state = ThreadApartmentState_MTA;
3999 mono_thread_init_apartment_state ();
4001 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
4003 /* FIXME: check signature of method */
4004 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4006 res = mono_runtime_invoke (method, NULL, pa, exc);
4008 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4012 mono_environment_exitcode_set (rval);
4014 mono_runtime_invoke (method, NULL, pa, exc);
4018 /* If the return type of Main is void, only
4019 * set the exitcode if an exception was thrown
4020 * (we don't want to blow away an
4021 * explicitly-set exit code)
4024 mono_environment_exitcode_set (rval);
4028 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
4034 * mono_install_runtime_invoke:
4035 * @func: Function to install
4037 * This is a VM internal routine
4040 mono_install_runtime_invoke (MonoInvokeFunc func)
4042 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4047 * mono_runtime_invoke_array:
4048 * @method: method to invoke
4049 * @obJ: object instance
4050 * @params: arguments to the method
4051 * @exc: exception information.
4053 * Invokes the method represented by @method on the object @obj.
4055 * obj is the 'this' pointer, it should be NULL for static
4056 * methods, a MonoObject* for object instances and a pointer to
4057 * the value type for value types.
4059 * The params array contains the arguments to the method with the
4060 * same convention: MonoObject* pointers for object instances and
4061 * pointers to the value type otherwise. The _invoke_array
4062 * variant takes a C# object[] as the params argument (MonoArray
4063 * *params): in this case the value types are boxed inside the
4064 * respective reference representation.
4066 * From unmanaged code you'll usually use the
4067 * mono_runtime_invoke() variant.
4069 * Note that this function doesn't handle virtual methods for
4070 * you, it will exec the exact method you pass: we still need to
4071 * expose a function to lookup the derived class implementation
4072 * of a virtual method (there are examples of this in the code,
4075 * You can pass NULL as the exc argument if you don't want to
4076 * catch exceptions, otherwise, *exc will be set to the exception
4077 * thrown, if any. if an exception is thrown, you can't use the
4078 * MonoObject* result from the function.
4080 * If the method returns a value type, it is boxed in an object
4084 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4087 MonoMethodSignature *sig = mono_method_signature (method);
4088 gpointer *pa = NULL;
4091 gboolean has_byref_nullables = FALSE;
4093 if (NULL != params) {
4094 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4095 for (i = 0; i < mono_array_length (params); i++) {
4096 MonoType *t = sig->params [i];
4102 case MONO_TYPE_BOOLEAN:
4105 case MONO_TYPE_CHAR:
4114 case MONO_TYPE_VALUETYPE:
4115 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4116 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4117 pa [i] = mono_array_get (params, MonoObject*, i);
4119 has_byref_nullables = TRUE;
4121 /* MS seems to create the objects if a null is passed in */
4122 if (!mono_array_get (params, MonoObject*, i))
4123 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4127 * We can't pass the unboxed vtype byref to the callee, since
4128 * that would mean the callee would be able to modify boxed
4129 * primitive types. So we (and MS) make a copy of the boxed
4130 * object, pass that to the callee, and replace the original
4131 * boxed object in the arg array with the copy.
4133 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4134 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4135 mono_array_setref (params, i, copy);
4138 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4141 case MONO_TYPE_STRING:
4142 case MONO_TYPE_OBJECT:
4143 case MONO_TYPE_CLASS:
4144 case MONO_TYPE_ARRAY:
4145 case MONO_TYPE_SZARRAY:
4147 pa [i] = mono_array_addr (params, MonoObject*, i);
4148 // FIXME: I need to check this code path
4150 pa [i] = mono_array_get (params, MonoObject*, i);
4152 case MONO_TYPE_GENERICINST:
4154 t = &t->data.generic_class->container_class->this_arg;
4156 t = &t->data.generic_class->container_class->byval_arg;
4158 case MONO_TYPE_PTR: {
4161 /* The argument should be an IntPtr */
4162 arg = mono_array_get (params, MonoObject*, i);
4166 g_assert (arg->vtable->klass == mono_defaults.int_class);
4167 pa [i] = ((MonoIntPtr*)arg)->m_value;
4172 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4177 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4180 if (mono_class_is_nullable (method->klass)) {
4181 /* Need to create a boxed vtype instead */
4187 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4191 obj = mono_object_new (mono_domain_get (), method->klass);
4192 g_assert (obj); /*maybe we should raise a TLE instead?*/
4193 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4194 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4196 if (method->klass->valuetype)
4197 o = mono_object_unbox (obj);
4200 } else if (method->klass->valuetype) {
4201 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4204 mono_runtime_invoke (method, o, pa, exc);
4207 if (mono_class_is_nullable (method->klass)) {
4208 MonoObject *nullable;
4210 /* Convert the unboxed vtype into a Nullable structure */
4211 nullable = mono_object_new (mono_domain_get (), method->klass);
4213 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4214 obj = mono_object_unbox (nullable);
4217 /* obj must be already unboxed if needed */
4218 res = mono_runtime_invoke (method, obj, pa, exc);
4220 if (sig->ret->type == MONO_TYPE_PTR) {
4221 MonoClass *pointer_class;
4222 static MonoMethod *box_method;
4224 MonoObject *box_exc;
4227 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4228 * convert it to a Pointer object.
4230 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4232 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4234 g_assert (res->vtable->klass == mono_defaults.int_class);
4235 box_args [0] = ((MonoIntPtr*)res)->m_value;
4236 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4237 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4238 g_assert (!box_exc);
4241 if (has_byref_nullables) {
4243 * The runtime invoke wrapper already converted byref nullables back,
4244 * and stored them in pa, we just need to copy them back to the
4247 for (i = 0; i < mono_array_length (params); i++) {
4248 MonoType *t = sig->params [i];
4250 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4251 mono_array_setref (params, i, pa [i]);
4260 arith_overflow (void)
4262 mono_raise_exception (mono_get_exception_overflow ());
4266 * mono_object_allocate:
4267 * @size: number of bytes to allocate
4269 * This is a very simplistic routine until we have our GC-aware
4272 * Returns: an allocated object of size @size, or NULL on failure.
4274 static inline void *
4275 mono_object_allocate (size_t size, MonoVTable *vtable)
4278 mono_stats.new_object_count++;
4279 ALLOC_OBJECT (o, vtable, size);
4285 * mono_object_allocate_ptrfree:
4286 * @size: number of bytes to allocate
4288 * Note that the memory allocated is not zeroed.
4289 * Returns: an allocated object of size @size, or NULL on failure.
4291 static inline void *
4292 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4295 mono_stats.new_object_count++;
4296 ALLOC_PTRFREE (o, vtable, size);
4300 static inline void *
4301 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4304 ALLOC_TYPED (o, size, vtable);
4305 mono_stats.new_object_count++;
4312 * @klass: the class of the object that we want to create
4314 * Returns: a newly created object whose definition is
4315 * looked up using @klass. This will not invoke any constructors,
4316 * so the consumer of this routine has to invoke any constructors on
4317 * its own to initialize the object.
4319 * It returns NULL on failure.
4322 mono_object_new (MonoDomain *domain, MonoClass *klass)
4326 MONO_ARCH_SAVE_REGS;
4327 vtable = mono_class_vtable (domain, klass);
4330 return mono_object_new_specific (vtable);
4334 * mono_object_new_pinned:
4336 * Same as mono_object_new, but the returned object will be pinned.
4337 * For SGEN, these objects will only be freed at appdomain unload.
4340 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4344 MONO_ARCH_SAVE_REGS;
4345 vtable = mono_class_vtable (domain, klass);
4350 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4352 return mono_object_new_specific (vtable);
4357 * mono_object_new_specific:
4358 * @vtable: the vtable of the object that we want to create
4360 * Returns: A newly created object with class and domain specified
4364 mono_object_new_specific (MonoVTable *vtable)
4368 MONO_ARCH_SAVE_REGS;
4370 /* check for is_com_object for COM Interop */
4371 if (vtable->remote || vtable->klass->is_com_object)
4374 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4377 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4380 mono_class_init (klass);
4382 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4384 vtable->domain->create_proxy_for_type_method = im;
4387 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4389 o = mono_runtime_invoke (im, NULL, pa, NULL);
4390 if (o != NULL) return o;
4393 return mono_object_new_alloc_specific (vtable);
4397 mono_object_new_alloc_specific (MonoVTable *vtable)
4401 if (!vtable->klass->has_references) {
4402 o = mono_object_new_ptrfree (vtable);
4403 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4404 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4406 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4407 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4409 if (G_UNLIKELY (vtable->klass->has_finalize))
4410 mono_object_register_finalizer (o);
4412 if (G_UNLIKELY (profile_allocs))
4413 mono_profiler_allocation (o, vtable->klass);
4418 mono_object_new_fast (MonoVTable *vtable)
4421 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4426 mono_object_new_ptrfree (MonoVTable *vtable)
4429 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4430 #if NEED_TO_ZERO_PTRFREE
4431 /* an inline memset is much faster for the common vcase of small objects
4432 * note we assume the allocated size is a multiple of sizeof (void*).
4434 if (vtable->klass->instance_size < 128) {
4436 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4437 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4443 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4450 mono_object_new_ptrfree_box (MonoVTable *vtable)
4453 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4454 /* the object will be boxed right away, no need to memzero it */
4459 * mono_class_get_allocation_ftn:
4461 * @for_box: the object will be used for boxing
4462 * @pass_size_in_words:
4464 * Return the allocation function appropriate for the given class.
4468 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4470 *pass_size_in_words = FALSE;
4472 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4473 profile_allocs = FALSE;
4475 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4476 return mono_object_new_specific;
4478 if (!vtable->klass->has_references) {
4479 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4481 return mono_object_new_ptrfree_box;
4482 return mono_object_new_ptrfree;
4485 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4487 return mono_object_new_fast;
4490 * FIXME: This is actually slower than mono_object_new_fast, because
4491 * of the overhead of parameter passing.
4494 *pass_size_in_words = TRUE;
4495 #ifdef GC_REDIRECT_TO_LOCAL
4496 return GC_local_gcj_fast_malloc;
4498 return GC_gcj_fast_malloc;
4503 return mono_object_new_specific;
4507 * mono_object_new_from_token:
4508 * @image: Context where the type_token is hosted
4509 * @token: a token of the type that we want to create
4511 * Returns: A newly created object whose definition is
4512 * looked up using @token in the @image image
4515 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4519 class = mono_class_get (image, token);
4521 return mono_object_new (domain, class);
4526 * mono_object_clone:
4527 * @obj: the object to clone
4529 * Returns: A newly created object who is a shallow copy of @obj
4532 mono_object_clone (MonoObject *obj)
4535 int size = obj->vtable->klass->instance_size;
4537 if (obj->vtable->klass->rank)
4538 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4540 o = mono_object_allocate (size, obj->vtable);
4542 if (obj->vtable->klass->has_references) {
4543 mono_gc_wbarrier_object_copy (o, obj);
4545 int size = obj->vtable->klass->instance_size;
4546 /* do not copy the sync state */
4547 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4549 if (G_UNLIKELY (profile_allocs))
4550 mono_profiler_allocation (o, obj->vtable->klass);
4552 if (obj->vtable->klass->has_finalize)
4553 mono_object_register_finalizer (o);
4558 * mono_array_full_copy:
4559 * @src: source array to copy
4560 * @dest: destination array
4562 * Copies the content of one array to another with exactly the same type and size.
4565 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4568 MonoClass *klass = src->obj.vtable->klass;
4570 MONO_ARCH_SAVE_REGS;
4572 g_assert (klass == dest->obj.vtable->klass);
4574 size = mono_array_length (src);
4575 g_assert (size == mono_array_length (dest));
4576 size *= mono_array_element_size (klass);
4578 if (klass->element_class->valuetype) {
4579 if (klass->element_class->has_references)
4580 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4582 mono_gc_memmove (&dest->vector, &src->vector, size);
4584 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4587 mono_gc_memmove (&dest->vector, &src->vector, size);
4592 * mono_array_clone_in_domain:
4593 * @domain: the domain in which the array will be cloned into
4594 * @array: the array to clone
4596 * This routine returns a copy of the array that is hosted on the
4597 * specified MonoDomain.
4600 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4605 MonoClass *klass = array->obj.vtable->klass;
4607 MONO_ARCH_SAVE_REGS;
4609 if (array->bounds == NULL) {
4610 size = mono_array_length (array);
4611 o = mono_array_new_full (domain, klass, &size, NULL);
4613 size *= mono_array_element_size (klass);
4615 if (klass->element_class->valuetype) {
4616 if (klass->element_class->has_references)
4617 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4619 mono_gc_memmove (&o->vector, &array->vector, size);
4621 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4624 mono_gc_memmove (&o->vector, &array->vector, size);
4629 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4630 size = mono_array_element_size (klass);
4631 for (i = 0; i < klass->rank; ++i) {
4632 sizes [i] = array->bounds [i].length;
4633 size *= array->bounds [i].length;
4634 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4636 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4638 if (klass->element_class->valuetype) {
4639 if (klass->element_class->has_references)
4640 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4642 mono_gc_memmove (&o->vector, &array->vector, size);
4644 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4647 mono_gc_memmove (&o->vector, &array->vector, size);
4655 * @array: the array to clone
4657 * Returns: A newly created array who is a shallow copy of @array
4660 mono_array_clone (MonoArray *array)
4662 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4665 /* helper macros to check for overflow when calculating the size of arrays */
4666 #ifdef MONO_BIG_ARRAYS
4667 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4668 #define MYGUINT_MAX MYGUINT64_MAX
4669 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4670 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4671 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4672 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4673 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4675 #define MYGUINT32_MAX 4294967295U
4676 #define MYGUINT_MAX MYGUINT32_MAX
4677 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4678 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4679 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4680 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4681 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4685 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4689 byte_len = mono_array_element_size (class);
4690 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4693 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4695 byte_len += sizeof (MonoArray);
4703 * mono_array_new_full:
4704 * @domain: domain where the object is created
4705 * @array_class: array class
4706 * @lengths: lengths for each dimension in the array
4707 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4709 * This routine creates a new array objects with the given dimensions,
4710 * lower bounds and type.
4713 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4715 uintptr_t byte_len, len, bounds_size;
4718 MonoArrayBounds *bounds;
4722 if (!array_class->inited)
4723 mono_class_init (array_class);
4727 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4728 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4730 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4734 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4736 for (i = 0; i < array_class->rank; ++i) {
4737 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4739 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4740 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4745 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4746 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4750 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4751 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4752 byte_len = (byte_len + 3) & ~3;
4753 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4754 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4755 byte_len += bounds_size;
4758 * Following three lines almost taken from mono_object_new ():
4759 * they need to be kept in sync.
4761 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4762 #ifndef HAVE_SGEN_GC
4763 if (!array_class->has_references) {
4764 o = mono_object_allocate_ptrfree (byte_len, vtable);
4765 #if NEED_TO_ZERO_PTRFREE
4766 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4768 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4769 o = mono_object_allocate_spec (byte_len, vtable);
4771 o = mono_object_allocate (byte_len, vtable);
4774 array = (MonoArray*)o;
4775 array->max_length = len;
4778 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4779 array->bounds = bounds;
4783 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4785 o = mono_gc_alloc_vector (vtable, byte_len, len);
4786 array = (MonoArray*)o;
4787 mono_stats.new_object_count++;
4789 bounds = array->bounds;
4793 for (i = 0; i < array_class->rank; ++i) {
4794 bounds [i].length = lengths [i];
4796 bounds [i].lower_bound = lower_bounds [i];
4800 if (G_UNLIKELY (profile_allocs))
4801 mono_profiler_allocation (o, array_class);
4808 * @domain: domain where the object is created
4809 * @eclass: element class
4810 * @n: number of array elements
4812 * This routine creates a new szarray with @n elements of type @eclass.
4815 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4819 MONO_ARCH_SAVE_REGS;
4821 ac = mono_array_class_get (eclass, 1);
4824 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4828 * mono_array_new_specific:
4829 * @vtable: a vtable in the appropriate domain for an initialized class
4830 * @n: number of array elements
4832 * This routine is a fast alternative to mono_array_new() for code which
4833 * can be sure about the domain it operates in.
4836 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4842 MONO_ARCH_SAVE_REGS;
4844 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4849 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4850 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4853 #ifndef HAVE_SGEN_GC
4854 if (!vtable->klass->has_references) {
4855 o = mono_object_allocate_ptrfree (byte_len, vtable);
4856 #if NEED_TO_ZERO_PTRFREE
4857 ((MonoArray*)o)->bounds = NULL;
4858 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4860 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4861 o = mono_object_allocate_spec (byte_len, vtable);
4863 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4864 o = mono_object_allocate (byte_len, vtable);
4867 ao = (MonoArray *)o;
4870 o = mono_gc_alloc_vector (vtable, byte_len, n);
4872 mono_stats.new_object_count++;
4875 if (G_UNLIKELY (profile_allocs))
4876 mono_profiler_allocation (o, vtable->klass);
4882 * mono_string_new_utf16:
4883 * @text: a pointer to an utf16 string
4884 * @len: the length of the string
4886 * Returns: A newly created string object which contains @text.
4889 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4893 s = mono_string_new_size (domain, len);
4894 g_assert (s != NULL);
4896 memcpy (mono_string_chars (s), text, len * 2);
4902 * mono_string_new_size:
4903 * @text: a pointer to an utf16 string
4904 * @len: the length of the string
4906 * Returns: A newly created string object of @len
4909 mono_string_new_size (MonoDomain *domain, gint32 len)
4913 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4915 /* overflow ? can't fit it, can't allocate it! */
4917 mono_gc_out_of_memory (-1);
4919 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4922 #ifndef HAVE_SGEN_GC
4923 s = mono_object_allocate_ptrfree (size, vtable);
4927 s = mono_gc_alloc_string (vtable, size, len);
4929 #if NEED_TO_ZERO_PTRFREE
4932 if (G_UNLIKELY (profile_allocs))
4933 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4939 * mono_string_new_len:
4940 * @text: a pointer to an utf8 string
4941 * @length: number of bytes in @text to consider
4943 * Returns: A newly created string object which contains @text.
4946 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4948 GError *error = NULL;
4949 MonoString *o = NULL;
4951 glong items_written;
4953 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
4956 o = mono_string_new_utf16 (domain, ut, items_written);
4958 g_error_free (error);
4967 * @text: a pointer to an utf8 string
4969 * Returns: A newly created string object which contains @text.
4972 mono_string_new (MonoDomain *domain, const char *text)
4974 GError *error = NULL;
4975 MonoString *o = NULL;
4977 glong items_written;
4982 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4985 o = mono_string_new_utf16 (domain, ut, items_written);
4987 g_error_free (error);
4990 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4995 MonoString *o = NULL;
4997 if (!g_utf8_validate (text, -1, &end))
5000 len = g_utf8_strlen (text, -1);
5001 o = mono_string_new_size (domain, len);
5002 str = mono_string_chars (o);
5004 while (text < end) {
5005 *str++ = g_utf8_get_char (text);
5006 text = g_utf8_next_char (text);
5013 * mono_string_new_wrapper:
5014 * @text: pointer to utf8 characters.
5016 * Helper function to create a string object from @text in the current domain.
5019 mono_string_new_wrapper (const char *text)
5021 MonoDomain *domain = mono_domain_get ();
5023 MONO_ARCH_SAVE_REGS;
5026 return mono_string_new (domain, text);
5033 * @class: the class of the value
5034 * @value: a pointer to the unboxed data
5036 * Returns: A newly created object which contains @value.
5039 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5045 g_assert (class->valuetype);
5046 if (mono_class_is_nullable (class))
5047 return mono_nullable_box (value, class);
5049 vtable = mono_class_vtable (domain, class);
5052 size = mono_class_instance_size (class);
5053 res = mono_object_new_alloc_specific (vtable);
5054 if (G_UNLIKELY (profile_allocs))
5055 mono_profiler_allocation (res, class);
5057 size = size - sizeof (MonoObject);
5060 g_assert (size == mono_class_value_size (class, NULL));
5061 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5063 #if NO_UNALIGNED_ACCESS
5064 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5068 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5071 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5074 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5077 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5080 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5084 if (class->has_finalize)
5085 mono_object_register_finalizer (res);
5091 * @dest: destination pointer
5092 * @src: source pointer
5093 * @klass: a valuetype class
5095 * Copy a valuetype from @src to @dest. This function must be used
5096 * when @klass contains references fields.
5099 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5101 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5105 * mono_value_copy_array:
5106 * @dest: destination array
5107 * @dest_idx: index in the @dest array
5108 * @src: source pointer
5109 * @count: number of items
5111 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5112 * This function must be used when @klass contains references fields.
5113 * Overlap is handled.
5116 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5118 int size = mono_array_element_size (dest->obj.vtable->klass);
5119 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5120 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5121 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5125 * mono_object_get_domain:
5126 * @obj: object to query
5128 * Returns: the MonoDomain where the object is hosted
5131 mono_object_get_domain (MonoObject *obj)
5133 return mono_object_domain (obj);
5137 * mono_object_get_class:
5138 * @obj: object to query
5140 * Returns: the MonOClass of the object.
5143 mono_object_get_class (MonoObject *obj)
5145 return mono_object_class (obj);
5148 * mono_object_get_size:
5149 * @o: object to query
5151 * Returns: the size, in bytes, of @o
5154 mono_object_get_size (MonoObject* o)
5156 MonoClass* klass = mono_object_class (o);
5157 if (klass == mono_defaults.string_class) {
5158 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5159 } else if (o->vtable->rank) {
5160 MonoArray *array = (MonoArray*)o;
5161 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5162 if (array->bounds) {
5165 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5169 return mono_class_instance_size (klass);
5174 * mono_object_unbox:
5175 * @obj: object to unbox
5177 * Returns: a pointer to the start of the valuetype boxed in this
5180 * This method will assert if the object passed is not a valuetype.
5183 mono_object_unbox (MonoObject *obj)
5185 /* add assert for valuetypes? */
5186 g_assert (obj->vtable->klass->valuetype);
5187 return ((char*)obj) + sizeof (MonoObject);
5191 * mono_object_isinst:
5193 * @klass: a pointer to a class
5195 * Returns: @obj if @obj is derived from @klass
5198 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5201 mono_class_init (klass);
5203 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5204 return mono_object_isinst_mbyref (obj, klass);
5209 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5213 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5222 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5223 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5227 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5228 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5231 MonoClass *oklass = vt->klass;
5232 if (oklass == mono_defaults.transparent_proxy_class)
5233 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5235 mono_class_setup_supertypes (klass);
5236 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5240 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5242 MonoDomain *domain = mono_domain_get ();
5244 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5245 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5246 MonoMethod *im = NULL;
5249 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5250 im = mono_object_get_virtual_method (rp, im);
5253 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5256 res = mono_runtime_invoke (im, rp, pa, NULL);
5258 if (*(MonoBoolean *) mono_object_unbox(res)) {
5259 /* Update the vtable of the remote type, so it can safely cast to this new type */
5260 mono_upgrade_remote_class (domain, obj, klass);
5269 * mono_object_castclass_mbyref:
5271 * @klass: a pointer to a class
5273 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5276 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5278 if (!obj) return NULL;
5279 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5281 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5283 "InvalidCastException"));
5288 MonoDomain *orig_domain;
5294 str_lookup (MonoDomain *domain, gpointer user_data)
5296 LDStrInfo *info = user_data;
5297 if (info->res || domain == info->orig_domain)
5299 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5305 mono_string_get_pinned (MonoString *str)
5309 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5310 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5312 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5313 news->length = mono_string_length (str);
5319 #define mono_string_get_pinned(str) (str)
5323 mono_string_is_interned_lookup (MonoString *str, int insert)
5325 MonoGHashTable *ldstr_table;
5329 domain = ((MonoObject *)str)->vtable->domain;
5330 ldstr_table = domain->ldstr_table;
5332 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5337 str = mono_string_get_pinned (str);
5339 mono_g_hash_table_insert (ldstr_table, str, str);
5343 LDStrInfo ldstr_info;
5344 ldstr_info.orig_domain = domain;
5345 ldstr_info.ins = str;
5346 ldstr_info.res = NULL;
5348 mono_domain_foreach (str_lookup, &ldstr_info);
5349 if (ldstr_info.res) {
5351 * the string was already interned in some other domain:
5352 * intern it in the current one as well.
5354 mono_g_hash_table_insert (ldstr_table, str, str);
5364 * mono_string_is_interned:
5365 * @o: String to probe
5367 * Returns whether the string has been interned.
5370 mono_string_is_interned (MonoString *o)
5372 return mono_string_is_interned_lookup (o, FALSE);
5376 * mono_string_intern:
5377 * @o: String to intern
5379 * Interns the string passed.
5380 * Returns: The interned string.
5383 mono_string_intern (MonoString *str)
5385 return mono_string_is_interned_lookup (str, TRUE);
5390 * @domain: the domain where the string will be used.
5391 * @image: a metadata context
5392 * @idx: index into the user string table.
5394 * Implementation for the ldstr opcode.
5395 * Returns: a loaded string from the @image/@idx combination.
5398 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5400 MONO_ARCH_SAVE_REGS;
5402 if (image->dynamic) {
5403 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5406 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5407 return NULL; /*FIXME we should probably be raising an exception here*/
5408 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5413 * mono_ldstr_metadata_sig
5414 * @domain: the domain for the string
5415 * @sig: the signature of a metadata string
5417 * Returns: a MonoString for a string stored in the metadata
5420 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5422 const char *str = sig;
5423 MonoString *o, *interned;
5426 len2 = mono_metadata_decode_blob_size (str, &str);
5429 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5430 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5433 guint16 *p2 = (guint16*)mono_string_chars (o);
5434 for (i = 0; i < len2; ++i) {
5435 *p2 = GUINT16_FROM_LE (*p2);
5441 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5443 /* o will get garbage collected */
5447 o = mono_string_get_pinned (o);
5449 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5456 * mono_string_to_utf8:
5457 * @s: a System.String
5459 * Returns the UTF8 representation for @s.
5460 * The resulting buffer needs to be freed with mono_free().
5462 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5465 mono_string_to_utf8 (MonoString *s)
5468 char *result = mono_string_to_utf8_checked (s, &error);
5470 if (!mono_error_ok (&error))
5471 mono_error_raise_exception (&error);
5476 * mono_string_to_utf8_checked:
5477 * @s: a System.String
5478 * @error: a MonoError.
5480 * Converts a MonoString to its UTF8 representation. May fail; check
5481 * @error to determine whether the conversion was successful.
5482 * The resulting buffer should be freed with mono_free().
5485 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5489 GError *gerror = NULL;
5491 mono_error_init (error);
5497 return g_strdup ("");
5499 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5501 mono_error_set_argument (error, "string", "%s", gerror->message);
5502 g_error_free (gerror);
5505 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5506 if (s->length > written) {
5507 /* allocate the total length and copy the part of the string that has been converted */
5508 char *as2 = g_malloc0 (s->length);
5509 memcpy (as2, as, written);
5518 * mono_string_to_utf8_ignore:
5521 * Converts a MonoString to its UTF8 representation. Will ignore
5522 * invalid surrogate pairs.
5523 * The resulting buffer should be freed with mono_free().
5527 mono_string_to_utf8_ignore (MonoString *s)
5536 return g_strdup ("");
5538 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5540 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5541 if (s->length > written) {
5542 /* allocate the total length and copy the part of the string that has been converted */
5543 char *as2 = g_malloc0 (s->length);
5544 memcpy (as2, as, written);
5553 * mono_string_to_utf8_image_ignore:
5554 * @s: a System.String
5556 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5559 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5561 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5565 * mono_string_to_utf8_mp_ignore:
5566 * @s: a System.String
5568 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5571 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5573 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5578 * mono_string_to_utf16:
5581 * Return an null-terminated array of the utf-16 chars
5582 * contained in @s. The result must be freed with g_free().
5583 * This is a temporary helper until our string implementation
5584 * is reworked to always include the null terminating char.
5587 mono_string_to_utf16 (MonoString *s)
5594 as = g_malloc ((s->length * 2) + 2);
5595 as [(s->length * 2)] = '\0';
5596 as [(s->length * 2) + 1] = '\0';
5599 return (gunichar2 *)(as);
5602 memcpy (as, mono_string_chars(s), s->length * 2);
5603 return (gunichar2 *)(as);
5607 * mono_string_from_utf16:
5608 * @data: the UTF16 string (LPWSTR) to convert
5610 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5612 * Returns: a MonoString.
5615 mono_string_from_utf16 (gunichar2 *data)
5617 MonoDomain *domain = mono_domain_get ();
5623 while (data [len]) len++;
5625 return mono_string_new_utf16 (domain, data, len);
5630 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5637 r = mono_string_to_utf8_ignore (s);
5639 r = mono_string_to_utf8_checked (s, error);
5640 if (!mono_error_ok (error))
5647 len = strlen (r) + 1;
5649 mp_s = mono_mempool_alloc (mp, len);
5651 mp_s = mono_image_alloc (image, len);
5653 memcpy (mp_s, r, len);
5661 * mono_string_to_utf8_image:
5662 * @s: a System.String
5664 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5667 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5669 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5673 * mono_string_to_utf8_mp:
5674 * @s: a System.String
5676 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5679 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5681 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5685 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5688 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5690 eh_callbacks = *cbs;
5693 MonoRuntimeExceptionHandlingCallbacks *
5694 mono_get_eh_callbacks (void)
5696 return &eh_callbacks;
5700 * mono_raise_exception:
5701 * @ex: exception object
5703 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5706 mono_raise_exception (MonoException *ex)
5709 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5710 * that will cause gcc to omit the function epilog, causing problems when
5711 * the JIT tries to walk the stack, since the return address on the stack
5712 * will point into the next function in the executable, not this one.
5714 eh_callbacks.mono_raise_exception (ex);
5718 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5720 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5724 * mono_wait_handle_new:
5725 * @domain: Domain where the object will be created
5726 * @handle: Handle for the wait handle
5728 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5731 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5733 MonoWaitHandle *res;
5734 gpointer params [1];
5735 static MonoMethod *handle_set;
5737 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5739 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5741 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5743 params [0] = &handle;
5744 mono_runtime_invoke (handle_set, res, params, NULL);
5750 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5752 static MonoClassField *f_os_handle;
5753 static MonoClassField *f_safe_handle;
5755 if (!f_os_handle && !f_safe_handle) {
5756 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5757 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5762 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5766 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5773 mono_runtime_capture_context (MonoDomain *domain)
5775 RuntimeInvokeFunction runtime_invoke;
5777 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5778 MonoMethod *method = mono_get_context_capture_method ();
5779 MonoMethod *wrapper;
5782 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5783 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5784 domain->capture_context_method = mono_compile_method (method);
5787 runtime_invoke = domain->capture_context_runtime_invoke;
5789 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5792 * mono_async_result_new:
5793 * @domain:domain where the object will be created.
5794 * @handle: wait handle.
5795 * @state: state to pass to AsyncResult
5796 * @data: C closure data.
5798 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5799 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5803 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5805 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5806 MonoObject *context = mono_runtime_capture_context (domain);
5807 /* we must capture the execution context from the original thread */
5809 MONO_OBJECT_SETREF (res, execution_context, context);
5810 /* note: result may be null if the flow is suppressed */
5814 MONO_OBJECT_SETREF (res, object_data, object_data);
5815 MONO_OBJECT_SETREF (res, async_state, state);
5817 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5819 res->sync_completed = FALSE;
5820 res->completed = FALSE;
5826 mono_message_init (MonoDomain *domain,
5827 MonoMethodMessage *this,
5828 MonoReflectionMethod *method,
5829 MonoArray *out_args)
5831 static MonoClass *object_array_klass;
5832 static MonoClass *byte_array_klass;
5833 static MonoClass *string_array_klass;
5834 MonoMethodSignature *sig = mono_method_signature (method->method);
5840 if (!object_array_klass) {
5843 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5845 byte_array_klass = klass;
5847 klass = mono_array_class_get (mono_defaults.string_class, 1);
5849 string_array_klass = klass;
5851 klass = mono_array_class_get (mono_defaults.object_class, 1);
5854 mono_atomic_store_release (&object_array_klass, klass);
5857 MONO_OBJECT_SETREF (this, method, method);
5859 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5860 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5861 this->async_result = NULL;
5862 this->call_type = CallType_Sync;
5864 names = g_new (char *, sig->param_count);
5865 mono_method_get_param_names (method->method, (const char **) names);
5866 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5868 for (i = 0; i < sig->param_count; i++) {
5869 name = mono_string_new (domain, names [i]);
5870 mono_array_setref (this->names, i, name);
5874 for (i = 0, j = 0; i < sig->param_count; i++) {
5875 if (sig->params [i]->byref) {
5877 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5878 mono_array_setref (this->args, i, arg);
5882 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5886 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5889 mono_array_set (this->arg_types, guint8, i, arg_type);
5894 * mono_remoting_invoke:
5895 * @real_proxy: pointer to a RealProxy object
5896 * @msg: The MonoMethodMessage to execute
5897 * @exc: used to store exceptions
5898 * @out_args: used to store output arguments
5900 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5901 * IMessage interface and it is not trivial to extract results from there. So
5902 * we call an helper method PrivateInvoke instead of calling
5903 * RealProxy::Invoke() directly.
5905 * Returns: the result object.
5908 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5909 MonoObject **exc, MonoArray **out_args)
5911 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5914 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5917 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5919 real_proxy->vtable->domain->private_invoke_method = im;
5922 pa [0] = real_proxy;
5927 return mono_runtime_invoke (im, NULL, pa, exc);
5931 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5932 MonoObject **exc, MonoArray **out_args)
5934 static MonoClass *object_array_klass;
5937 MonoMethodSignature *sig;
5939 int i, j, outarg_count = 0;
5941 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5943 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5944 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5945 target = tp->rp->unwrapped_server;
5947 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5951 domain = mono_domain_get ();
5952 method = msg->method->method;
5953 sig = mono_method_signature (method);
5955 for (i = 0; i < sig->param_count; i++) {
5956 if (sig->params [i]->byref)
5960 if (!object_array_klass) {
5963 klass = mono_array_class_get (mono_defaults.object_class, 1);
5966 mono_memory_barrier ();
5967 object_array_klass = klass;
5970 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5971 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5974 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5976 for (i = 0, j = 0; i < sig->param_count; i++) {
5977 if (sig->params [i]->byref) {
5979 arg = mono_array_get (msg->args, gpointer, i);
5980 mono_array_setref (*out_args, j, arg);
5989 * mono_object_to_string:
5991 * @exc: Any exception thrown by ToString (). May be NULL.
5993 * Returns: the result of calling ToString () on an object.
5996 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5998 static MonoMethod *to_string = NULL;
6004 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6006 method = mono_object_get_virtual_method (obj, to_string);
6008 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
6012 * mono_print_unhandled_exception:
6013 * @exc: The exception
6015 * Prints the unhandled exception.
6018 mono_print_unhandled_exception (MonoObject *exc)
6021 char *message = (char*)"";
6022 gboolean free_message = FALSE;
6025 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6026 message = g_strdup ("OutOfMemoryException");
6027 free_message = TRUE;
6030 if (((MonoException*)exc)->native_trace_ips) {
6031 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6032 free_message = TRUE;
6034 str = mono_object_to_string (exc, NULL);
6036 message = mono_string_to_utf8_checked (str, &error);
6037 if (!mono_error_ok (&error)) {
6038 mono_error_cleanup (&error);
6039 message = (char *) "";
6041 free_message = TRUE;
6048 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6049 * exc->vtable->klass->name, message);
6051 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6058 * mono_delegate_ctor:
6059 * @this: pointer to an uninitialized delegate object
6060 * @target: target object
6061 * @addr: pointer to native code
6064 * Initialize a delegate and sets a specific method, not the one
6065 * associated with addr. This is useful when sharing generic code.
6066 * In that case addr will most probably not be associated with the
6067 * correct instantiation of the method.
6070 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6072 MonoDelegate *delegate = (MonoDelegate *)this;
6079 delegate->method = method;
6081 class = this->vtable->klass;
6082 mono_stats.delegate_creations++;
6084 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6086 method = mono_marshal_get_remoting_invoke (method);
6087 delegate->method_ptr = mono_compile_method (method);
6088 MONO_OBJECT_SETREF (delegate, target, target);
6089 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6090 method = mono_marshal_get_unbox_wrapper (method);
6091 delegate->method_ptr = mono_compile_method (method);
6092 MONO_OBJECT_SETREF (delegate, target, target);
6094 delegate->method_ptr = addr;
6095 MONO_OBJECT_SETREF (delegate, target, target);
6098 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6102 * mono_delegate_ctor:
6103 * @this: pointer to an uninitialized delegate object
6104 * @target: target object
6105 * @addr: pointer to native code
6107 * This is used to initialize a delegate.
6110 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6112 MonoDomain *domain = mono_domain_get ();
6114 MonoMethod *method = NULL;
6118 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6120 if (!ji && domain != mono_get_root_domain ())
6121 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6123 method = ji->method;
6124 g_assert (!method->klass->generic_container);
6127 mono_delegate_ctor_with_method (this, target, addr, method);
6131 * mono_method_call_message_new:
6132 * @method: method to encapsulate
6133 * @params: parameters to the method
6134 * @invoke: optional, delegate invoke.
6135 * @cb: async callback delegate.
6136 * @state: state passed to the async callback.
6138 * Translates arguments pointers into a MonoMethodMessage.
6141 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6142 MonoDelegate **cb, MonoObject **state)
6144 MonoDomain *domain = mono_domain_get ();
6145 MonoMethodSignature *sig = mono_method_signature (method);
6146 MonoMethodMessage *msg;
6149 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6152 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6153 count = sig->param_count - 2;
6155 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6156 count = sig->param_count;
6159 for (i = 0; i < count; i++) {
6164 if (sig->params [i]->byref)
6165 vpos = *((gpointer *)params [i]);
6169 type = sig->params [i]->type;
6170 class = mono_class_from_mono_type (sig->params [i]);
6172 if (class->valuetype)
6173 arg = mono_value_box (domain, class, vpos);
6175 arg = *((MonoObject **)vpos);
6177 mono_array_setref (msg->args, i, arg);
6180 if (cb != NULL && state != NULL) {
6181 *cb = *((MonoDelegate **)params [i]);
6183 *state = *((MonoObject **)params [i]);
6190 * mono_method_return_message_restore:
6192 * Restore results from message based processing back to arguments pointers
6195 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6197 MonoMethodSignature *sig = mono_method_signature (method);
6198 int i, j, type, size, out_len;
6200 if (out_args == NULL)
6202 out_len = mono_array_length (out_args);
6206 for (i = 0, j = 0; i < sig->param_count; i++) {
6207 MonoType *pt = sig->params [i];
6212 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6214 arg = mono_array_get (out_args, gpointer, j);
6217 g_assert (type != MONO_TYPE_VOID);
6219 if (MONO_TYPE_IS_REFERENCE (pt)) {
6220 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6223 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6224 size = mono_class_value_size (class, NULL);
6225 if (class->has_references)
6226 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6228 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6230 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6231 mono_gc_bzero (*((gpointer *)params [i]), size);
6241 * mono_load_remote_field:
6242 * @this: pointer to an object
6243 * @klass: klass of the object containing @field
6244 * @field: the field to load
6245 * @res: a storage to store the result
6247 * This method is called by the runtime on attempts to load fields of
6248 * transparent proxy objects. @this points to such TP, @klass is the class of
6249 * the object containing @field. @res is a storage location which can be
6250 * used to store the result.
6252 * Returns: an address pointing to the value of field.
6255 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6257 static MonoMethod *getter = NULL;
6258 MonoDomain *domain = mono_domain_get ();
6259 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6260 MonoClass *field_class;
6261 MonoMethodMessage *msg;
6262 MonoArray *out_args;
6266 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6267 g_assert (res != NULL);
6269 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6270 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6275 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6279 field_class = mono_class_from_mono_type (field->type);
6281 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6282 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6283 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6285 full_name = mono_type_get_full_name (klass);
6286 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6287 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6290 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6292 if (exc) mono_raise_exception ((MonoException *)exc);
6294 if (mono_array_length (out_args) == 0)
6297 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6299 if (field_class->valuetype) {
6300 return ((char *)*res) + sizeof (MonoObject);
6306 * mono_load_remote_field_new:
6311 * Missing documentation.
6314 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6316 static MonoMethod *getter = NULL;
6317 MonoDomain *domain = mono_domain_get ();
6318 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6319 MonoClass *field_class;
6320 MonoMethodMessage *msg;
6321 MonoArray *out_args;
6322 MonoObject *exc, *res;
6325 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6327 field_class = mono_class_from_mono_type (field->type);
6329 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6331 if (field_class->valuetype) {
6332 res = mono_object_new (domain, field_class);
6333 val = ((gchar *) res) + sizeof (MonoObject);
6337 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6342 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6346 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6347 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6349 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6351 full_name = mono_type_get_full_name (klass);
6352 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6353 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6356 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6358 if (exc) mono_raise_exception ((MonoException *)exc);
6360 if (mono_array_length (out_args) == 0)
6363 res = mono_array_get (out_args, MonoObject *, 0);
6369 * mono_store_remote_field:
6370 * @this: pointer to an object
6371 * @klass: klass of the object containing @field
6372 * @field: the field to load
6373 * @val: the value/object to store
6375 * This method is called by the runtime on attempts to store fields of
6376 * transparent proxy objects. @this points to such TP, @klass is the class of
6377 * the object containing @field. @val is the new value to store in @field.
6380 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6382 static MonoMethod *setter = NULL;
6383 MonoDomain *domain = mono_domain_get ();
6384 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6385 MonoClass *field_class;
6386 MonoMethodMessage *msg;
6387 MonoArray *out_args;
6392 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6394 field_class = mono_class_from_mono_type (field->type);
6396 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6397 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6398 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6403 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6407 if (field_class->valuetype)
6408 arg = mono_value_box (domain, field_class, val);
6410 arg = *((MonoObject **)val);
6413 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6414 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6416 full_name = mono_type_get_full_name (klass);
6417 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6418 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6419 mono_array_setref (msg->args, 2, arg);
6422 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6424 if (exc) mono_raise_exception ((MonoException *)exc);
6428 * mono_store_remote_field_new:
6434 * Missing documentation
6437 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6439 static MonoMethod *setter = NULL;
6440 MonoDomain *domain = mono_domain_get ();
6441 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6442 MonoClass *field_class;
6443 MonoMethodMessage *msg;
6444 MonoArray *out_args;
6448 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6450 field_class = mono_class_from_mono_type (field->type);
6452 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6453 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6454 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6459 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6463 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6464 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6466 full_name = mono_type_get_full_name (klass);
6467 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6468 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6469 mono_array_setref (msg->args, 2, arg);
6472 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6474 if (exc) mono_raise_exception ((MonoException *)exc);
6478 * mono_create_ftnptr:
6480 * Given a function address, create a function descriptor for it.
6481 * This is only needed on some platforms.
6484 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6486 return callbacks.create_ftnptr (domain, addr);
6490 * mono_get_addr_from_ftnptr:
6492 * Given a pointer to a function descriptor, return the function address.
6493 * This is only needed on some platforms.
6496 mono_get_addr_from_ftnptr (gpointer descr)
6498 return callbacks.get_addr_from_ftnptr (descr);
6502 * mono_string_chars:
6505 * Returns a pointer to the UCS16 characters stored in the MonoString
6508 mono_string_chars (MonoString *s)
6514 * mono_string_length:
6517 * Returns the lenght in characters of the string
6520 mono_string_length (MonoString *s)
6526 * mono_array_length:
6527 * @array: a MonoArray*
6529 * Returns the total number of elements in the array. This works for
6530 * both vectors and multidimensional arrays.
6533 mono_array_length (MonoArray *array)
6535 return array->max_length;
6539 * mono_array_addr_with_size:
6540 * @array: a MonoArray*
6541 * @size: size of the array elements
6542 * @idx: index into the array
6544 * Returns the address of the @idx element in the array.
6547 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6549 return ((char*)(array)->vector) + size * idx;