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-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
83 free_main_args (void);
86 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
89 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
90 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
91 static CRITICAL_SECTION ldstr_section;
93 static gboolean profile_allocs = TRUE;
96 mono_runtime_object_init (MonoObject *this)
98 MonoMethod *method = NULL;
99 MonoClass *klass = this->vtable->klass;
101 method = mono_class_get_method_from_name (klass, ".ctor", 0);
104 if (method->klass->valuetype)
105 this = mono_object_unbox (this);
106 mono_runtime_invoke (method, this, NULL, NULL);
109 /* The pseudo algorithm for type initialization from the spec
110 Note it doesn't say anything about domains - only threads.
112 2. If the type is initialized you are done.
113 2.1. If the type is not yet initialized, try to take an
115 2.2. If successful, record this thread as responsible for
116 initializing the type and proceed to step 2.3.
117 2.2.1. If not, see whether this thread or any thread
118 waiting for this thread to complete already holds the lock.
119 2.2.2. If so, return since blocking would create a deadlock. This thread
120 will now see an incompletely initialized state for the type,
121 but no deadlock will arise.
122 2.2.3 If not, block until the type is initialized then return.
123 2.3 Initialize the parent type and then all interfaces implemented
125 2.4 Execute the type initialization code for this type.
126 2.5 Mark the type as initialized, release the initialization lock,
127 awaken any threads waiting for this type to be initialized,
134 guint32 initializing_tid;
135 guint32 waiting_count;
137 CRITICAL_SECTION initialization_section;
138 } TypeInitializationLock;
140 /* for locking access to type_initialization_hash and blocked_thread_hash */
141 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
142 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
143 static CRITICAL_SECTION type_initialization_section;
145 /* from vtable to lock */
146 static GHashTable *type_initialization_hash;
148 /* from thread id to thread id being waited on */
149 static GHashTable *blocked_thread_hash;
152 static MonoThread *main_thread;
154 /* Functions supplied by the runtime */
155 static MonoRuntimeCallbacks callbacks;
158 * mono_thread_set_main:
159 * @thread: thread to set as the main thread
161 * This function can be used to instruct the runtime to treat @thread
162 * as the main thread, ie, the thread that would normally execute the Main()
163 * method. This basically means that at the end of @thread, the runtime will
164 * wait for the existing foreground threads to quit and other such details.
167 mono_thread_set_main (MonoThread *thread)
169 static gboolean registered = FALSE;
172 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
176 main_thread = thread;
180 mono_thread_get_main (void)
186 mono_type_initialization_init (void)
188 InitializeCriticalSection (&type_initialization_section);
189 type_initialization_hash = g_hash_table_new (NULL, NULL);
190 blocked_thread_hash = g_hash_table_new (NULL, NULL);
191 InitializeCriticalSection (&ldstr_section);
195 mono_type_initialization_cleanup (void)
198 /* This is causing race conditions with
199 * mono_release_type_locks
201 DeleteCriticalSection (&type_initialization_section);
202 g_hash_table_destroy (type_initialization_hash);
203 type_initialization_hash = NULL;
205 DeleteCriticalSection (&ldstr_section);
206 g_hash_table_destroy (blocked_thread_hash);
207 blocked_thread_hash = NULL;
213 * get_type_init_exception_for_vtable:
215 * Return the stored type initialization exception for VTABLE.
217 static MonoException*
218 get_type_init_exception_for_vtable (MonoVTable *vtable)
220 MonoDomain *domain = vtable->domain;
221 MonoClass *klass = vtable->klass;
225 g_assert (vtable->init_failed);
228 * If the initializing thread was rudely aborted, the exception is not stored
232 mono_domain_lock (domain);
233 if (domain->type_init_exception_hash)
234 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
235 mono_domain_unlock (domain);
238 if (klass->name_space && *klass->name_space)
239 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
241 full_name = g_strdup (klass->name);
242 ex = mono_get_exception_type_initialization (full_name, NULL);
249 * mono_runtime_class_init:
250 * @vtable: vtable that needs to be initialized
252 * This routine calls the class constructor for @vtable.
255 mono_runtime_class_init (MonoVTable *vtable)
257 mono_runtime_class_init_full (vtable, TRUE);
261 * mono_runtime_class_init_full:
262 * @vtable that neeeds to be initialized
263 * @raise_exception is TRUE, exceptions are raised intead of returned
267 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
270 MonoException *exc_to_throw;
271 MonoMethod *method = NULL;
277 if (vtable->initialized)
281 klass = vtable->klass;
283 if (!klass->image->checked_module_cctor) {
284 mono_image_check_for_module_cctor (klass->image);
285 if (klass->image->has_module_cctor) {
286 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
287 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
290 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
295 method = mono_class_get_cctor (klass);
298 MonoDomain *domain = vtable->domain;
299 TypeInitializationLock *lock;
300 guint32 tid = GetCurrentThreadId();
301 int do_initialization = 0;
302 MonoDomain *last_domain = NULL;
304 mono_type_initialization_lock ();
305 /* double check... */
306 if (vtable->initialized) {
307 mono_type_initialization_unlock ();
310 if (vtable->init_failed) {
311 mono_type_initialization_unlock ();
313 /* The type initialization already failed once, rethrow the same exception */
315 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
316 return get_type_init_exception_for_vtable (vtable);
318 lock = g_hash_table_lookup (type_initialization_hash, vtable);
320 /* This thread will get to do the initialization */
321 if (mono_domain_get () != domain) {
322 /* Transfer into the target domain */
323 last_domain = mono_domain_get ();
324 if (!mono_domain_set (domain, FALSE)) {
325 vtable->initialized = 1;
326 mono_type_initialization_unlock ();
328 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
329 return mono_get_exception_appdomain_unloaded ();
332 lock = g_malloc (sizeof(TypeInitializationLock));
333 InitializeCriticalSection (&lock->initialization_section);
334 lock->initializing_tid = tid;
335 lock->waiting_count = 1;
337 /* grab the vtable lock while this thread still owns type_initialization_section */
338 EnterCriticalSection (&lock->initialization_section);
339 g_hash_table_insert (type_initialization_hash, vtable, lock);
340 do_initialization = 1;
343 TypeInitializationLock *pending_lock;
345 if (lock->initializing_tid == tid || lock->done) {
346 mono_type_initialization_unlock ();
349 /* see if the thread doing the initialization is already blocked on this thread */
350 blocked = GUINT_TO_POINTER (lock->initializing_tid);
351 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
352 if (pending_lock->initializing_tid == tid) {
353 if (!pending_lock->done) {
354 mono_type_initialization_unlock ();
357 /* the thread doing the initialization is blocked on this thread,
358 but on a lock that has already been freed. It just hasn't got
363 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
365 ++lock->waiting_count;
366 /* record the fact that we are waiting on the initializing thread */
367 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
369 mono_type_initialization_unlock ();
371 if (do_initialization) {
372 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
374 /* If the initialization failed, mark the class as unusable. */
375 /* Avoid infinite loops */
377 (klass->image == mono_defaults.corlib &&
378 !strcmp (klass->name_space, "System") &&
379 !strcmp (klass->name, "TypeInitializationException")))) {
380 vtable->init_failed = 1;
382 if (klass->name_space && *klass->name_space)
383 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
385 full_name = g_strdup (klass->name);
386 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
390 * Store the exception object so it could be thrown on subsequent
393 mono_domain_lock (domain);
394 if (!domain->type_init_exception_hash)
395 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
396 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
397 mono_domain_unlock (domain);
401 mono_domain_set (last_domain, TRUE);
403 LeaveCriticalSection (&lock->initialization_section);
405 /* this just blocks until the initializing thread is done */
406 EnterCriticalSection (&lock->initialization_section);
407 LeaveCriticalSection (&lock->initialization_section);
410 mono_type_initialization_lock ();
411 if (lock->initializing_tid != tid)
412 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
413 --lock->waiting_count;
414 if (lock->waiting_count == 0) {
415 DeleteCriticalSection (&lock->initialization_section);
416 g_hash_table_remove (type_initialization_hash, vtable);
419 mono_memory_barrier ();
420 if (!vtable->init_failed)
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
424 if (vtable->init_failed) {
425 /* Either we were the initializing thread or we waited for the initialization */
427 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
428 return get_type_init_exception_for_vtable (vtable);
431 vtable->initialized = 1;
438 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
440 MonoVTable *vtable = (MonoVTable*)key;
442 TypeInitializationLock *lock = (TypeInitializationLock*) value;
443 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
446 * Have to set this since it cannot be set by the normal code in
447 * mono_runtime_class_init (). In this case, the exception object is not stored,
448 * and get_type_init_exception_for_class () needs to be aware of this.
450 vtable->init_failed = 1;
451 LeaveCriticalSection (&lock->initialization_section);
452 --lock->waiting_count;
453 if (lock->waiting_count == 0) {
454 DeleteCriticalSection (&lock->initialization_section);
463 mono_release_type_locks (MonoInternalThread *thread)
465 mono_type_initialization_lock ();
466 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
467 mono_type_initialization_unlock ();
471 default_trampoline (MonoMethod *method)
477 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
479 g_assert_not_reached ();
485 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
487 g_error ("remoting not installed");
492 default_delegate_trampoline (MonoClass *klass)
494 g_assert_not_reached ();
498 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
499 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
500 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
501 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
502 static MonoImtThunkBuilder imt_thunk_builder = NULL;
503 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
504 #if (MONO_IMT_SIZE > 32)
505 #error "MONO_IMT_SIZE cannot be larger than 32"
509 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
511 memcpy (&callbacks, cbs, sizeof (*cbs));
514 MonoRuntimeCallbacks*
515 mono_get_runtime_callbacks (void)
521 mono_install_trampoline (MonoTrampoline func)
523 arch_create_jit_trampoline = func? func: default_trampoline;
527 mono_install_jump_trampoline (MonoJumpTrampoline func)
529 arch_create_jump_trampoline = func? func: default_jump_trampoline;
533 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
535 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
539 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
541 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
545 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
546 imt_thunk_builder = func;
549 static MonoCompileFunc default_mono_compile_method = NULL;
552 * mono_install_compile_method:
553 * @func: function to install
555 * This is a VM internal routine
558 mono_install_compile_method (MonoCompileFunc func)
560 default_mono_compile_method = func;
564 * mono_compile_method:
565 * @method: The method to compile.
567 * This JIT-compiles the method, and returns the pointer to the native code
571 mono_compile_method (MonoMethod *method)
573 if (!default_mono_compile_method) {
574 g_error ("compile method called on uninitialized runtime");
577 return default_mono_compile_method (method);
581 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
583 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
587 mono_runtime_create_delegate_trampoline (MonoClass *klass)
589 return arch_create_delegate_trampoline (klass);
592 static MonoFreeMethodFunc default_mono_free_method = NULL;
595 * mono_install_free_method:
596 * @func: pointer to the MonoFreeMethodFunc used to release a method
598 * This is an internal VM routine, it is used for the engines to
599 * register a handler to release the resources associated with a method.
601 * Methods are freed when no more references to the delegate that holds
605 mono_install_free_method (MonoFreeMethodFunc func)
607 default_mono_free_method = func;
611 * mono_runtime_free_method:
612 * @domain; domain where the method is hosted
613 * @method: method to release
615 * This routine is invoked to free the resources associated with
616 * a method that has been JIT compiled. This is used to discard
617 * methods that were used only temporarily (for example, used in marshalling)
621 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
623 if (default_mono_free_method != NULL)
624 default_mono_free_method (domain, method);
626 mono_method_clear_object (domain, method);
628 mono_free_method (method);
632 * The vtables in the root appdomain are assumed to be reachable by other
633 * roots, and we don't use typed allocation in the other domains.
636 /* The sync block is no longer a GC pointer */
637 #define GC_HEADER_BITMAP (0)
639 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
642 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
644 MonoClassField *field;
650 max_size = mono_class_data_size (class) / sizeof (gpointer);
652 max_size = class->instance_size / sizeof (gpointer);
653 if (max_size > size) {
654 g_assert (offset <= 0);
655 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
660 /*An Ephemeron cannot be marked by sgen*/
661 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
663 memset (bitmap, 0, size / 8);
668 for (p = class; p != NULL; p = p->parent) {
669 gpointer iter = NULL;
670 while ((field = mono_class_get_fields (p, &iter))) {
674 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
676 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
679 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
682 /* FIXME: should not happen, flag as type load error */
683 if (field->type->byref)
686 if (static_fields && field->offset == -1)
690 pos = field->offset / sizeof (gpointer);
693 type = mono_type_get_underlying_type (field->type);
694 switch (type->type) {
697 case MONO_TYPE_FNPTR:
699 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
704 if (class->image != mono_defaults.corlib)
707 case MONO_TYPE_STRING:
708 case MONO_TYPE_SZARRAY:
709 case MONO_TYPE_CLASS:
710 case MONO_TYPE_OBJECT:
711 case MONO_TYPE_ARRAY:
712 g_assert ((field->offset % sizeof(gpointer)) == 0);
714 g_assert (pos < size || pos <= max_size);
715 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
716 *max_set = MAX (*max_set, pos);
718 case MONO_TYPE_GENERICINST:
719 if (!mono_type_generic_inst_is_valuetype (type)) {
720 g_assert ((field->offset % sizeof(gpointer)) == 0);
722 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
723 *max_set = MAX (*max_set, pos);
728 case MONO_TYPE_VALUETYPE: {
729 MonoClass *fclass = mono_class_from_mono_type (field->type);
730 if (fclass->has_references) {
731 /* remove the object header */
732 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
746 case MONO_TYPE_BOOLEAN:
750 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
761 * mono_class_compute_bitmap:
763 * Mono internal function to compute a bitmap of reference fields in a class.
766 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
768 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
773 * similar to the above, but sets the bits in the bitmap for any non-ref field
774 * and ignores static fields
777 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
779 MonoClassField *field;
784 max_size = class->instance_size / sizeof (gpointer);
785 if (max_size >= size) {
786 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
789 for (p = class; p != NULL; p = p->parent) {
790 gpointer iter = NULL;
791 while ((field = mono_class_get_fields (p, &iter))) {
794 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
796 /* FIXME: should not happen, flag as type load error */
797 if (field->type->byref)
800 pos = field->offset / sizeof (gpointer);
803 type = mono_type_get_underlying_type (field->type);
804 switch (type->type) {
805 #if SIZEOF_VOID_P == 8
809 case MONO_TYPE_FNPTR:
814 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
815 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
816 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
819 #if SIZEOF_VOID_P == 4
823 case MONO_TYPE_FNPTR:
828 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
829 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
830 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
836 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
837 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
838 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
841 case MONO_TYPE_BOOLEAN:
844 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
846 case MONO_TYPE_STRING:
847 case MONO_TYPE_SZARRAY:
848 case MONO_TYPE_CLASS:
849 case MONO_TYPE_OBJECT:
850 case MONO_TYPE_ARRAY:
852 case MONO_TYPE_GENERICINST:
853 if (!mono_type_generic_inst_is_valuetype (type)) {
858 case MONO_TYPE_VALUETYPE: {
859 MonoClass *fclass = mono_class_from_mono_type (field->type);
860 /* remove the object header */
861 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
865 g_assert_not_reached ();
874 * mono_class_insecure_overlapping:
875 * check if a class with explicit layout has references and non-references
876 * fields overlapping.
878 * Returns: TRUE if it is insecure to load the type.
881 mono_class_insecure_overlapping (MonoClass *klass)
885 gsize default_bitmap [4] = {0};
887 gsize default_nrbitmap [4] = {0};
888 int i, insecure = FALSE;
891 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
892 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
894 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
895 int idx = i % (sizeof (bitmap [0]) * 8);
896 if (bitmap [idx] & nrbitmap [idx]) {
901 if (bitmap != default_bitmap)
903 if (nrbitmap != default_nrbitmap)
906 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
914 mono_string_alloc (int length)
916 return mono_string_new_size (mono_domain_get (), length);
920 mono_class_compute_gc_descriptor (MonoClass *class)
924 gsize default_bitmap [4] = {0};
925 static gboolean gcj_inited = FALSE;
930 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
931 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
932 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
933 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
935 #ifdef HAVE_GC_GCJ_MALLOC
937 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
941 #ifdef GC_REDIRECT_TO_LOCAL
942 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
943 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
945 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
946 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
951 mono_loader_unlock ();
955 mono_class_init (class);
957 if (class->gc_descr_inited)
960 class->gc_descr_inited = TRUE;
961 class->gc_descr = GC_NO_DESCRIPTOR;
963 bitmap = default_bitmap;
964 if (class == mono_defaults.string_class) {
965 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
966 } else if (class->rank) {
967 mono_class_compute_gc_descriptor (class->element_class);
968 if (!class->element_class->valuetype) {
970 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
971 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
972 class->name_space, class->name);*/
974 /* remove the object header */
975 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
976 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
977 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
978 class->name_space, class->name);*/
979 if (bitmap != default_bitmap)
983 /*static int count = 0;
986 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
987 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
989 if (class->gc_descr == GC_NO_DESCRIPTOR)
990 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
992 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
993 if (bitmap != default_bitmap)
999 * field_is_special_static:
1000 * @fklass: The MonoClass to look up.
1001 * @field: The MonoClassField describing the field.
1003 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1004 * SPECIAL_STATIC_NONE otherwise.
1007 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1009 MonoCustomAttrInfo *ainfo;
1011 ainfo = mono_custom_attrs_from_field (fklass, field);
1014 for (i = 0; i < ainfo->num_attrs; ++i) {
1015 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1016 if (klass->image == mono_defaults.corlib) {
1017 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1018 mono_custom_attrs_free (ainfo);
1019 return SPECIAL_STATIC_THREAD;
1021 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1022 mono_custom_attrs_free (ainfo);
1023 return SPECIAL_STATIC_CONTEXT;
1027 mono_custom_attrs_free (ainfo);
1028 return SPECIAL_STATIC_NONE;
1031 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1032 #define mix(a,b,c) { \
1033 a -= c; a ^= rot(c, 4); c += b; \
1034 b -= a; b ^= rot(a, 6); a += c; \
1035 c -= b; c ^= rot(b, 8); b += a; \
1036 a -= c; a ^= rot(c,16); c += b; \
1037 b -= a; b ^= rot(a,19); a += c; \
1038 c -= b; c ^= rot(b, 4); b += a; \
1040 #define final(a,b,c) { \
1041 c ^= b; c -= rot(b,14); \
1042 a ^= c; a -= rot(c,11); \
1043 b ^= a; b -= rot(a,25); \
1044 c ^= b; c -= rot(b,16); \
1045 a ^= c; a -= rot(c,4); \
1046 b ^= a; b -= rot(a,14); \
1047 c ^= b; c -= rot(b,24); \
1051 * mono_method_get_imt_slot:
1053 * The IMT slot is embedded into AOTed code, so this must return the same value
1054 * for the same method across all executions. This means:
1055 * - pointers shouldn't be used as hash values.
1056 * - mono_metadata_str_hash () should be used for hashing strings.
1059 mono_method_get_imt_slot (MonoMethod *method)
1061 MonoMethodSignature *sig;
1063 guint32 *hashes_start, *hashes;
1067 /* This can be used to stress tests the collision code */
1071 * We do this to simplify generic sharing. It will hurt
1072 * performance in cases where a class implements two different
1073 * instantiations of the same generic interface.
1074 * The code in build_imt_slots () depends on this.
1076 if (method->is_inflated)
1077 method = ((MonoMethodInflated*)method)->declaring;
1079 sig = mono_method_signature (method);
1080 hashes_count = sig->param_count + 4;
1081 hashes_start = malloc (hashes_count * sizeof (guint32));
1082 hashes = hashes_start;
1084 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1085 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1086 method->klass->name_space, method->klass->name, method->name);
1087 g_assert_not_reached ();
1090 /* Initialize hashes */
1091 hashes [0] = mono_metadata_str_hash (method->klass->name);
1092 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1093 hashes [2] = mono_metadata_str_hash (method->name);
1094 hashes [3] = mono_metadata_type_hash (sig->ret);
1095 for (i = 0; i < sig->param_count; i++) {
1096 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1099 /* Setup internal state */
1100 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1102 /* Handle most of the hashes */
1103 while (hashes_count > 3) {
1112 /* Handle the last 3 hashes (all the case statements fall through) */
1113 switch (hashes_count) {
1114 case 3 : c += hashes [2];
1115 case 2 : b += hashes [1];
1116 case 1 : a += hashes [0];
1118 case 0: /* nothing left to add */
1122 free (hashes_start);
1123 /* Report the result */
1124 return c % MONO_IMT_SIZE;
1133 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1134 guint32 imt_slot = mono_method_get_imt_slot (method);
1135 MonoImtBuilderEntry *entry;
1137 if (slot_num >= 0 && imt_slot != slot_num) {
1138 /* we build just a single imt slot and this is not it */
1142 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1143 entry->key = method;
1144 entry->value.vtable_slot = vtable_slot;
1145 entry->next = imt_builder [imt_slot];
1146 if (imt_builder [imt_slot] != NULL) {
1147 entry->children = imt_builder [imt_slot]->children + 1;
1148 if (entry->children == 1) {
1149 mono_stats.imt_slots_with_collisions++;
1150 *imt_collisions_bitmap |= (1 << imt_slot);
1153 entry->children = 0;
1154 mono_stats.imt_used_slots++;
1156 imt_builder [imt_slot] = entry;
1159 char *method_name = mono_method_full_name (method, TRUE);
1160 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1161 method, method_name, imt_slot, vtable_slot, entry->children);
1162 g_free (method_name);
1169 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1171 MonoMethod *method = e->key;
1172 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1176 method->klass->name_space,
1177 method->klass->name,
1180 printf (" * %s: NULL\n", message);
1186 compare_imt_builder_entries (const void *p1, const void *p2) {
1187 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1188 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1190 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1194 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1196 int count = end - start;
1197 int chunk_start = out_array->len;
1200 for (i = start; i < end; ++i) {
1201 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1202 item->key = sorted_array [i]->key;
1203 item->value = sorted_array [i]->value;
1204 item->has_target_code = sorted_array [i]->has_target_code;
1205 item->is_equals = TRUE;
1207 item->check_target_idx = out_array->len + 1;
1209 item->check_target_idx = 0;
1210 g_ptr_array_add (out_array, item);
1213 int middle = start + count / 2;
1214 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1216 item->key = sorted_array [middle]->key;
1217 item->is_equals = FALSE;
1218 g_ptr_array_add (out_array, item);
1219 imt_emit_ir (sorted_array, start, middle, out_array);
1220 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1226 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1227 int number_of_entries = entries->children + 1;
1228 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1229 GPtrArray *result = g_ptr_array_new ();
1230 MonoImtBuilderEntry *current_entry;
1233 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1234 sorted_array [i] = current_entry;
1236 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1238 /*for (i = 0; i < number_of_entries; i++) {
1239 print_imt_entry (" sorted array:", sorted_array [i], i);
1242 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1244 free (sorted_array);
1249 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1251 if (imt_builder_entry != NULL) {
1252 if (imt_builder_entry->children == 0 && !fail_tramp) {
1253 /* No collision, return the vtable slot contents */
1254 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1256 /* Collision, build the thunk */
1257 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1260 result = imt_thunk_builder (vtable, domain,
1261 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1262 for (i = 0; i < imt_ir->len; ++i)
1263 g_free (g_ptr_array_index (imt_ir, i));
1264 g_ptr_array_free (imt_ir, TRUE);
1276 static MonoImtBuilderEntry*
1277 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1280 * LOCKING: requires the loader and domain locks.
1284 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1288 guint32 imt_collisions_bitmap = 0;
1289 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1290 int method_count = 0;
1291 gboolean record_method_count_for_max_collisions = FALSE;
1292 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1295 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1297 for (i = 0; i < klass->interface_offsets_count; ++i) {
1298 MonoClass *iface = klass->interfaces_packed [i];
1299 int interface_offset = klass->interface_offsets_packed [i];
1300 int method_slot_in_interface, vt_slot;
1302 if (mono_class_has_variant_generic_params (iface))
1303 has_variant_iface = TRUE;
1305 vt_slot = interface_offset;
1306 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1309 if (slot_num >= 0 && iface->is_inflated) {
1311 * The imt slot of the method is the same as for its declaring method,
1312 * see the comment in mono_method_get_imt_slot (), so we can
1313 * avoid inflating methods which will be discarded by
1314 * add_imt_builder_entry anyway.
1316 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1317 if (mono_method_get_imt_slot (method) != slot_num) {
1322 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1323 if (method->is_generic) {
1324 has_generic_virtual = TRUE;
1329 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1330 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1335 if (extra_interfaces) {
1336 int interface_offset = klass->vtable_size;
1338 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1339 MonoClass* iface = list_item->data;
1340 int method_slot_in_interface;
1341 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1342 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1343 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1345 interface_offset += iface->method.count;
1348 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1349 /* overwrite the imt slot only if we're building all the entries or if
1350 * we're building this specific one
1352 if (slot_num < 0 || i == slot_num) {
1353 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1356 if (imt_builder [i]) {
1357 MonoImtBuilderEntry *entry;
1359 /* Link entries with imt_builder [i] */
1360 for (entry = entries; entry->next; entry = entry->next) {
1362 MonoMethod *method = (MonoMethod*)entry->key;
1363 char *method_name = mono_method_full_name (method, TRUE);
1364 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1365 g_free (method_name);
1368 entry->next = imt_builder [i];
1369 entries->children += imt_builder [i]->children + 1;
1371 imt_builder [i] = entries;
1374 if (has_generic_virtual || has_variant_iface) {
1376 * There might be collisions later when the the thunk is expanded.
1378 imt_collisions_bitmap |= (1 << i);
1381 * The IMT thunk might be called with an instance of one of the
1382 * generic virtual methods, so has to fallback to the IMT trampoline.
1384 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1386 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1389 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1393 if (imt_builder [i] != NULL) {
1394 int methods_in_slot = imt_builder [i]->children + 1;
1395 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1396 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1397 record_method_count_for_max_collisions = TRUE;
1399 method_count += methods_in_slot;
1403 mono_stats.imt_number_of_methods += method_count;
1404 if (record_method_count_for_max_collisions) {
1405 mono_stats.imt_method_count_when_max_collisions = method_count;
1408 for (i = 0; i < MONO_IMT_SIZE; i++) {
1409 MonoImtBuilderEntry* entry = imt_builder [i];
1410 while (entry != NULL) {
1411 MonoImtBuilderEntry* next = entry->next;
1417 /* we OR the bitmap since we may build just a single imt slot at a time */
1418 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1422 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1423 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1427 * mono_vtable_build_imt_slot:
1428 * @vtable: virtual object table struct
1429 * @imt_slot: slot in the IMT table
1431 * Fill the given @imt_slot in the IMT table of @vtable with
1432 * a trampoline or a thunk for the case of collisions.
1433 * This is part of the internal mono API.
1435 * LOCKING: Take the domain lock.
1438 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1440 gpointer *imt = (gpointer*)vtable;
1441 imt -= MONO_IMT_SIZE;
1442 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1444 /* no support for extra interfaces: the proxy objects will need
1445 * to build the complete IMT
1446 * Update and heck needs to ahppen inside the proper domain lock, as all
1447 * the changes made to a MonoVTable.
1449 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1450 mono_domain_lock (vtable->domain);
1451 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1452 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1453 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1454 mono_domain_unlock (vtable->domain);
1455 mono_loader_unlock ();
1460 * The first two free list entries both belong to the wait list: The
1461 * first entry is the pointer to the head of the list and the second
1462 * entry points to the last element. That way appending and removing
1463 * the first element are both O(1) operations.
1465 #ifdef MONO_SMALL_CONFIG
1466 #define NUM_FREE_LISTS 6
1468 #define NUM_FREE_LISTS 12
1470 #define FIRST_FREE_LIST_SIZE 64
1471 #define MAX_WAIT_LENGTH 50
1472 #define THUNK_THRESHOLD 10
1475 * LOCKING: The domain lock must be held.
1478 init_thunk_free_lists (MonoDomain *domain)
1480 if (domain->thunk_free_lists)
1482 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1486 list_index_for_size (int item_size)
1489 int size = FIRST_FREE_LIST_SIZE;
1491 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1500 * mono_method_alloc_generic_virtual_thunk:
1502 * @size: size in bytes
1504 * Allocs size bytes to be used for the code of a generic virtual
1505 * thunk. It's either allocated from the domain's code manager or
1506 * reused from a previously invalidated piece.
1508 * LOCKING: The domain lock must be held.
1511 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1513 static gboolean inited = FALSE;
1514 static int generic_virtual_thunks_size = 0;
1518 MonoThunkFreeList **l;
1520 init_thunk_free_lists (domain);
1522 size += sizeof (guint32);
1523 if (size < sizeof (MonoThunkFreeList))
1524 size = sizeof (MonoThunkFreeList);
1526 i = list_index_for_size (size);
1527 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1528 if ((*l)->size >= size) {
1529 MonoThunkFreeList *item = *l;
1531 return ((guint32*)item) + 1;
1535 /* no suitable item found - search lists of larger sizes */
1536 while (++i < NUM_FREE_LISTS) {
1537 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1540 g_assert (item->size > size);
1541 domain->thunk_free_lists [i] = item->next;
1542 return ((guint32*)item) + 1;
1545 /* still nothing found - allocate it */
1547 mono_counters_register ("Generic virtual thunk bytes",
1548 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1551 generic_virtual_thunks_size += size;
1553 p = mono_domain_code_reserve (domain, size);
1556 mono_domain_lock (domain);
1557 if (!domain->generic_virtual_thunks)
1558 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1559 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1560 mono_domain_unlock (domain);
1566 * LOCKING: The domain lock must be held.
1569 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1572 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1573 gboolean found = FALSE;
1575 mono_domain_lock (domain);
1576 if (!domain->generic_virtual_thunks)
1577 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1578 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1580 mono_domain_unlock (domain);
1583 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1585 init_thunk_free_lists (domain);
1587 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1588 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1589 int length = item->length;
1592 /* unlink the first item from the wait list */
1593 domain->thunk_free_lists [0] = item->next;
1594 domain->thunk_free_lists [0]->length = length - 1;
1596 i = list_index_for_size (item->size);
1598 /* put it in the free list */
1599 item->next = domain->thunk_free_lists [i];
1600 domain->thunk_free_lists [i] = item;
1604 if (domain->thunk_free_lists [1]) {
1605 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1606 domain->thunk_free_lists [0]->length++;
1608 g_assert (!domain->thunk_free_lists [0]);
1610 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1611 domain->thunk_free_lists [0]->length = 1;
1615 typedef struct _GenericVirtualCase {
1619 struct _GenericVirtualCase *next;
1620 } GenericVirtualCase;
1623 * get_generic_virtual_entries:
1625 * Return IMT entries for the generic virtual method instances and
1626 * variant interface methods for vtable slot
1629 static MonoImtBuilderEntry*
1630 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1632 GenericVirtualCase *list;
1633 MonoImtBuilderEntry *entries;
1635 mono_domain_lock (domain);
1636 if (!domain->generic_virtual_cases)
1637 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1639 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1642 for (; list; list = list->next) {
1643 MonoImtBuilderEntry *entry;
1645 if (list->count < THUNK_THRESHOLD)
1648 entry = g_new0 (MonoImtBuilderEntry, 1);
1649 entry->key = list->method;
1650 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1651 entry->has_target_code = 1;
1653 entry->children = entries->children + 1;
1654 entry->next = entries;
1658 mono_domain_unlock (domain);
1660 /* FIXME: Leaking memory ? */
1665 * mono_method_add_generic_virtual_invocation:
1667 * @vtable_slot: pointer to the vtable slot
1668 * @method: the inflated generic virtual method
1669 * @code: the method's code
1671 * Registers a call via unmanaged code to a generic virtual method
1672 * instantiation or variant interface method. If the number of calls reaches a threshold
1673 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1674 * virtual method thunk.
1677 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1678 gpointer *vtable_slot,
1679 MonoMethod *method, gpointer code)
1681 static gboolean inited = FALSE;
1682 static int num_added = 0;
1684 GenericVirtualCase *gvc, *list;
1685 MonoImtBuilderEntry *entries;
1689 mono_domain_lock (domain);
1690 if (!domain->generic_virtual_cases)
1691 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1693 /* Check whether the case was already added */
1694 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1697 if (gvc->method == method)
1702 /* If not found, make a new one */
1704 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1705 gvc->method = method;
1708 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1713 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1719 if (++gvc->count == THUNK_THRESHOLD) {
1720 gpointer *old_thunk = *vtable_slot;
1721 gpointer vtable_trampoline = NULL;
1722 gpointer imt_trampoline = NULL;
1724 if ((gpointer)vtable_slot < (gpointer)vtable) {
1725 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1726 int imt_slot = MONO_IMT_SIZE + displacement;
1728 /* Force the rebuild of the thunk at the next call */
1729 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1730 *vtable_slot = imt_trampoline;
1732 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1734 entries = get_generic_virtual_entries (domain, vtable_slot);
1736 sorted = imt_sort_slot_entries (entries);
1738 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1742 MonoImtBuilderEntry *next = entries->next;
1747 for (i = 0; i < sorted->len; ++i)
1748 g_free (g_ptr_array_index (sorted, i));
1749 g_ptr_array_free (sorted, TRUE);
1752 #ifndef __native_client__
1753 /* We don't re-use any thunks as there is a lot of overhead */
1754 /* to deleting and re-using code in Native Client. */
1755 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1756 invalidate_generic_virtual_thunk (domain, old_thunk);
1760 mono_domain_unlock (domain);
1763 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1766 * mono_class_vtable:
1767 * @domain: the application domain
1768 * @class: the class to initialize
1770 * VTables are domain specific because we create domain specific code, and
1771 * they contain the domain specific static class data.
1772 * On failure, NULL is returned, and class->exception_type is set.
1775 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1777 return mono_class_vtable_full (domain, class, FALSE);
1781 * mono_class_vtable_full:
1782 * @domain: the application domain
1783 * @class: the class to initialize
1784 * @raise_on_error if an exception should be raised on failure or not
1786 * VTables are domain specific because we create domain specific code, and
1787 * they contain the domain specific static class data.
1790 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1792 MonoClassRuntimeInfo *runtime_info;
1796 if (class->exception_type) {
1798 mono_raise_exception (mono_class_get_exception_for_failure (class));
1802 /* this check can be inlined in jitted code, too */
1803 runtime_info = class->runtime_info;
1804 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1805 return runtime_info->domain_vtables [domain->domain_id];
1806 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1810 * mono_class_try_get_vtable:
1811 * @domain: the application domain
1812 * @class: the class to initialize
1814 * This function tries to get the associated vtable from @class if
1815 * it was already created.
1818 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1820 MonoClassRuntimeInfo *runtime_info;
1824 runtime_info = class->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1831 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1834 MonoClassRuntimeInfo *runtime_info, *old_info;
1835 MonoClassField *field;
1837 int i, vtable_slots;
1838 int imt_table_bytes = 0;
1839 guint32 vtable_size, class_size;
1842 gpointer *interface_offsets;
1844 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1845 mono_domain_lock (domain);
1846 runtime_info = class->runtime_info;
1847 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1848 mono_domain_unlock (domain);
1849 mono_loader_unlock ();
1850 return runtime_info->domain_vtables [domain->domain_id];
1852 if (!class->inited || class->exception_type) {
1853 if (!mono_class_init (class) || class->exception_type) {
1854 mono_domain_unlock (domain);
1855 mono_loader_unlock ();
1857 mono_raise_exception (mono_class_get_exception_for_failure (class));
1862 /* Array types require that their element type be valid*/
1863 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1864 MonoClass *element_class = class->element_class;
1865 if (!element_class->inited)
1866 mono_class_init (element_class);
1868 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1869 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1870 mono_class_setup_vtable (element_class);
1872 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1873 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1874 if (class->exception_type == MONO_EXCEPTION_NONE)
1875 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1876 mono_domain_unlock (domain);
1877 mono_loader_unlock ();
1879 mono_raise_exception (mono_class_get_exception_for_failure (class));
1885 * For some classes, mono_class_init () already computed class->vtable_size, and
1886 * that is all that is needed because of the vtable trampolines.
1888 if (!class->vtable_size)
1889 mono_class_setup_vtable (class);
1891 if (class->generic_class && !class->vtable)
1892 mono_class_check_vtable_constraints (class, NULL);
1894 /* Initialize klass->has_finalize */
1895 mono_class_has_finalizer (class);
1897 if (class->exception_type) {
1898 mono_domain_unlock (domain);
1899 mono_loader_unlock ();
1901 mono_raise_exception (mono_class_get_exception_for_failure (class));
1905 vtable_slots = class->vtable_size;
1906 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1907 class_size = mono_class_data_size (class);
1912 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1913 if (class->interface_offsets_count) {
1914 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1915 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1916 mono_stats.imt_number_of_tables++;
1917 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1920 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1921 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1924 mono_stats.used_class_count++;
1925 mono_stats.class_vtable_size += vtable_size;
1926 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1929 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1931 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1933 vt->rank = class->rank;
1934 vt->domain = domain;
1936 mono_class_compute_gc_descriptor (class);
1938 * We can't use typed allocation in the non-root domains, since the
1939 * collector needs the GC descriptor stored in the vtable even after
1940 * the mempool containing the vtable is destroyed when the domain is
1941 * unloaded. An alternative might be to allocate vtables in the GC
1942 * heap, but this does not seem to work (it leads to crashes inside
1943 * libgc). If that approach is tried, two gc descriptors need to be
1944 * allocated for each class: one for the root domain, and one for all
1945 * other domains. The second descriptor should contain a bit for the
1946 * vtable field in MonoObject, since we can no longer assume the
1947 * vtable is reachable by other roots after the appdomain is unloaded.
1949 #ifdef HAVE_BOEHM_GC
1950 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1951 vt->gc_descr = GC_NO_DESCRIPTOR;
1954 vt->gc_descr = class->gc_descr;
1957 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1958 if (class->has_static_refs) {
1959 gpointer statics_gc_descr;
1961 gsize default_bitmap [4] = {0};
1964 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1965 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1966 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1967 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1968 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1969 if (bitmap != default_bitmap)
1972 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1974 vt->has_static_fields = TRUE;
1975 mono_stats.class_static_data_size += class_size;
1980 while ((field = mono_class_get_fields (class, &iter))) {
1981 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1983 if (mono_field_is_deleted (field))
1985 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1986 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1987 if (special_static != SPECIAL_STATIC_NONE) {
1988 guint32 size, offset;
1990 gsize default_bitmap [4] = {0};
1994 if (mono_type_is_reference (field->type)) {
1995 default_bitmap [0] = 1;
1997 bitmap = default_bitmap;
1998 } else if (mono_type_is_struct (field->type)) {
1999 fclass = mono_class_from_mono_type (field->type);
2000 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
2002 default_bitmap [0] = 0;
2004 bitmap = default_bitmap;
2006 size = mono_type_size (field->type, &align);
2007 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2008 if (!domain->special_static_fields)
2009 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2010 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2011 if (bitmap != default_bitmap)
2014 * This marks the field as special static to speed up the
2015 * checks in mono_field_static_get/set_value ().
2021 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2022 MonoClass *fklass = mono_class_from_mono_type (field->type);
2023 const char *data = mono_field_get_data (field);
2025 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2026 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2027 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2030 if (fklass->valuetype) {
2031 memcpy (t, data, mono_class_value_size (fklass, NULL));
2033 /* it's a pointer type: add check */
2034 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2041 vt->max_interface_id = class->max_interface_id;
2042 vt->interface_bitmap = class->interface_bitmap;
2044 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2045 // class->name, class->interface_offsets_count);
2047 if (! ARCH_USE_IMT) {
2048 /* initialize interface offsets */
2049 for (i = 0; i < class->interface_offsets_count; ++i) {
2050 int interface_id = class->interfaces_packed [i]->interface_id;
2051 int slot = class->interface_offsets_packed [i];
2052 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2056 /* class_vtable_array keeps an array of created vtables
2058 g_ptr_array_add (domain->class_vtable_array, vt);
2059 /* class->runtime_info is protected by the loader lock, both when
2060 * it it enlarged and when it is stored info.
2063 old_info = class->runtime_info;
2064 if (old_info && old_info->max_domain >= domain->domain_id) {
2065 /* someone already created a large enough runtime info */
2066 mono_memory_barrier ();
2067 old_info->domain_vtables [domain->domain_id] = vt;
2069 int new_size = domain->domain_id;
2071 new_size = MAX (new_size, old_info->max_domain);
2073 /* make the new size a power of two */
2075 while (new_size > i)
2078 /* this is a bounded memory retention issue: may want to
2079 * handle it differently when we'll have a rcu-like system.
2081 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2082 runtime_info->max_domain = new_size - 1;
2083 /* copy the stuff from the older info */
2085 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2087 runtime_info->domain_vtables [domain->domain_id] = vt;
2089 mono_memory_barrier ();
2090 class->runtime_info = runtime_info;
2093 /* Initialize vtable */
2094 if (callbacks.get_vtable_trampoline) {
2095 // This also covers the AOT case
2096 for (i = 0; i < class->vtable_size; ++i) {
2097 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2100 mono_class_setup_vtable (class);
2102 for (i = 0; i < class->vtable_size; ++i) {
2105 if ((cm = class->vtable [i]))
2106 vt->vtable [i] = arch_create_jit_trampoline (cm);
2110 if (ARCH_USE_IMT && imt_table_bytes) {
2111 /* Now that the vtable is full, we can actually fill up the IMT */
2112 if (callbacks.get_imt_trampoline) {
2113 /* lazy construction of the IMT entries enabled */
2114 for (i = 0; i < MONO_IMT_SIZE; ++i)
2115 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2117 build_imt (class, vt, domain, interface_offsets, NULL);
2121 mono_domain_unlock (domain);
2122 mono_loader_unlock ();
2124 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2125 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2126 mono_raise_exception (mono_class_get_exception_for_failure (class));
2128 /* make sure the parent is initialized */
2129 /*FIXME shouldn't this fail the current type?*/
2131 mono_class_vtable_full (domain, class->parent, raise_on_error);
2133 /*FIXME check for OOM*/
2134 vt->type = mono_type_get_object (domain, &class->byval_arg);
2135 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2136 /* This is unregistered in
2137 unregister_vtable_reflection_type() in
2139 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2140 if (class->contextbound)
2149 * mono_class_proxy_vtable:
2150 * @domain: the application domain
2151 * @remove_class: the remote class
2153 * Creates a vtable for transparent proxies. It is basically
2154 * a copy of the real vtable of the class wrapped in @remote_class,
2155 * but all function pointers invoke the remoting functions, and
2156 * vtable->klass points to the transparent proxy class, and not to @class.
2159 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2162 MonoVTable *vt, *pvt;
2163 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2165 GSList *extra_interfaces = NULL;
2166 MonoClass *class = remote_class->proxy_class;
2167 gpointer *interface_offsets;
2171 #ifdef COMPRESSED_INTERFACE_BITMAP
2175 vt = mono_class_vtable (domain, class);
2176 g_assert (vt); /*FIXME property handle failure*/
2177 max_interface_id = vt->max_interface_id;
2179 /* Calculate vtable space for extra interfaces */
2180 for (j = 0; j < remote_class->interface_count; j++) {
2181 MonoClass* iclass = remote_class->interfaces[j];
2185 /*FIXME test for interfaces with variant generic arguments*/
2186 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2187 continue; /* interface implemented by the class */
2188 if (g_slist_find (extra_interfaces, iclass))
2191 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2193 method_count = mono_class_num_methods (iclass);
2195 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2196 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2198 for (i = 0; i < ifaces->len; ++i) {
2199 MonoClass *ic = g_ptr_array_index (ifaces, i);
2200 /*FIXME test for interfaces with variant generic arguments*/
2201 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2202 continue; /* interface implemented by the class */
2203 if (g_slist_find (extra_interfaces, ic))
2205 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2206 method_count += mono_class_num_methods (ic);
2208 g_ptr_array_free (ifaces, TRUE);
2211 extra_interface_vtsize += method_count * sizeof (gpointer);
2212 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2216 mono_stats.imt_number_of_tables++;
2217 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2218 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2219 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2221 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2222 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2225 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2227 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2229 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2231 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2232 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2234 pvt->klass = mono_defaults.transparent_proxy_class;
2235 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2236 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2238 /* initialize vtable */
2239 mono_class_setup_vtable (class);
2240 for (i = 0; i < class->vtable_size; ++i) {
2243 if ((cm = class->vtable [i]))
2244 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2246 pvt->vtable [i] = NULL;
2249 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2250 /* create trampolines for abstract methods */
2251 for (k = class; k; k = k->parent) {
2253 gpointer iter = NULL;
2254 while ((m = mono_class_get_methods (k, &iter)))
2255 if (!pvt->vtable [m->slot])
2256 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2260 pvt->max_interface_id = max_interface_id;
2261 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2262 #ifdef COMPRESSED_INTERFACE_BITMAP
2263 bitmap = g_malloc0 (bsize);
2265 bitmap = mono_domain_alloc0 (domain, bsize);
2268 if (! ARCH_USE_IMT) {
2269 /* initialize interface offsets */
2270 for (i = 0; i < class->interface_offsets_count; ++i) {
2271 int interface_id = class->interfaces_packed [i]->interface_id;
2272 int slot = class->interface_offsets_packed [i];
2273 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2276 for (i = 0; i < class->interface_offsets_count; ++i) {
2277 int interface_id = class->interfaces_packed [i]->interface_id;
2278 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2281 if (extra_interfaces) {
2282 int slot = class->vtable_size;
2288 /* Create trampolines for the methods of the interfaces */
2289 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2290 interf = list_item->data;
2292 if (! ARCH_USE_IMT) {
2293 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2295 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2299 while ((cm = mono_class_get_methods (interf, &iter)))
2300 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2302 slot += mono_class_num_methods (interf);
2304 if (! ARCH_USE_IMT) {
2305 g_slist_free (extra_interfaces);
2310 /* Now that the vtable is full, we can actually fill up the IMT */
2311 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2312 if (extra_interfaces) {
2313 g_slist_free (extra_interfaces);
2317 #ifdef COMPRESSED_INTERFACE_BITMAP
2318 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2319 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2320 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2323 pvt->interface_bitmap = bitmap;
2329 * mono_class_field_is_special_static:
2331 * Returns whether @field is a thread/context static field.
2334 mono_class_field_is_special_static (MonoClassField *field)
2336 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2338 if (mono_field_is_deleted (field))
2340 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2341 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2348 * mono_class_field_get_special_static_type:
2349 * @field: The MonoClassField describing the field.
2351 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2352 * SPECIAL_STATIC_NONE otherwise.
2355 mono_class_field_get_special_static_type (MonoClassField *field)
2357 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2358 return SPECIAL_STATIC_NONE;
2359 if (mono_field_is_deleted (field))
2360 return SPECIAL_STATIC_NONE;
2361 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2362 return field_is_special_static (field->parent, field);
2363 return SPECIAL_STATIC_NONE;
2367 * mono_class_has_special_static_fields:
2369 * Returns whenever @klass has any thread/context static fields.
2372 mono_class_has_special_static_fields (MonoClass *klass)
2374 MonoClassField *field;
2378 while ((field = mono_class_get_fields (klass, &iter))) {
2379 g_assert (field->parent == klass);
2380 if (mono_class_field_is_special_static (field))
2388 * create_remote_class_key:
2389 * Creates an array of pointers that can be used as a hash key for a remote class.
2390 * The first element of the array is the number of pointers.
2393 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2398 if (remote_class == NULL) {
2399 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2400 key = g_malloc (sizeof(gpointer) * 3);
2401 key [0] = GINT_TO_POINTER (2);
2402 key [1] = mono_defaults.marshalbyrefobject_class;
2403 key [2] = extra_class;
2405 key = g_malloc (sizeof(gpointer) * 2);
2406 key [0] = GINT_TO_POINTER (1);
2407 key [1] = extra_class;
2410 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2411 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2412 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2413 key [1] = remote_class->proxy_class;
2415 // Keep the list of interfaces sorted
2416 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2417 if (extra_class && remote_class->interfaces [i] > extra_class) {
2418 key [j++] = extra_class;
2421 key [j] = remote_class->interfaces [i];
2424 key [j] = extra_class;
2426 // Replace the old class. The interface list is the same
2427 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2428 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2429 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2430 for (i = 0; i < remote_class->interface_count; i++)
2431 key [2 + i] = remote_class->interfaces [i];
2439 * copy_remote_class_key:
2441 * Make a copy of KEY in the domain and return the copy.
2444 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2446 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2447 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2449 memcpy (mp_key, key, key_size);
2455 * mono_remote_class:
2456 * @domain: the application domain
2457 * @class_name: name of the remote class
2459 * Creates and initializes a MonoRemoteClass object for a remote type.
2461 * Can raise an exception on failure.
2464 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2467 MonoRemoteClass *rc;
2468 gpointer* key, *mp_key;
2471 key = create_remote_class_key (NULL, proxy_class);
2473 mono_domain_lock (domain);
2474 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2478 mono_domain_unlock (domain);
2482 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2483 if (!mono_error_ok (&error)) {
2485 mono_domain_unlock (domain);
2486 mono_error_raise_exception (&error);
2489 mp_key = copy_remote_class_key (domain, key);
2493 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2494 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2495 rc->interface_count = 1;
2496 rc->interfaces [0] = proxy_class;
2497 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2499 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2500 rc->interface_count = 0;
2501 rc->proxy_class = proxy_class;
2504 rc->default_vtable = NULL;
2505 rc->xdomain_vtable = NULL;
2506 rc->proxy_class_name = name;
2507 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2509 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2511 mono_domain_unlock (domain);
2516 * clone_remote_class:
2517 * Creates a copy of the remote_class, adding the provided class or interface
2519 static MonoRemoteClass*
2520 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2522 MonoRemoteClass *rc;
2523 gpointer* key, *mp_key;
2525 key = create_remote_class_key (remote_class, extra_class);
2526 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2532 mp_key = copy_remote_class_key (domain, key);
2536 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2538 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2539 rc->proxy_class = remote_class->proxy_class;
2540 rc->interface_count = remote_class->interface_count + 1;
2542 // Keep the list of interfaces sorted, since the hash key of
2543 // the remote class depends on this
2544 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2545 if (remote_class->interfaces [i] > extra_class && i == j)
2546 rc->interfaces [j++] = extra_class;
2547 rc->interfaces [j] = remote_class->interfaces [i];
2550 rc->interfaces [j] = extra_class;
2552 // Replace the old class. The interface array is the same
2553 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2554 rc->proxy_class = extra_class;
2555 rc->interface_count = remote_class->interface_count;
2556 if (rc->interface_count > 0)
2557 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2560 rc->default_vtable = NULL;
2561 rc->xdomain_vtable = NULL;
2562 rc->proxy_class_name = remote_class->proxy_class_name;
2564 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2570 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2572 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2573 mono_domain_lock (domain);
2574 if (rp->target_domain_id != -1) {
2575 if (remote_class->xdomain_vtable == NULL)
2576 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2577 mono_domain_unlock (domain);
2578 mono_loader_unlock ();
2579 return remote_class->xdomain_vtable;
2581 if (remote_class->default_vtable == NULL) {
2584 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2585 klass = mono_class_from_mono_type (type);
2586 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2587 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2589 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2592 mono_domain_unlock (domain);
2593 mono_loader_unlock ();
2594 return remote_class->default_vtable;
2598 * mono_upgrade_remote_class:
2599 * @domain: the application domain
2600 * @tproxy: the proxy whose remote class has to be upgraded.
2601 * @klass: class to which the remote class can be casted.
2603 * Updates the vtable of the remote class by adding the necessary method slots
2604 * and interface offsets so it can be safely casted to klass. klass can be a
2605 * class or an interface.
2608 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2610 MonoTransparentProxy *tproxy;
2611 MonoRemoteClass *remote_class;
2612 gboolean redo_vtable;
2614 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2615 mono_domain_lock (domain);
2617 tproxy = (MonoTransparentProxy*) proxy_object;
2618 remote_class = tproxy->remote_class;
2620 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2623 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2624 if (remote_class->interfaces [i] == klass)
2625 redo_vtable = FALSE;
2628 redo_vtable = (remote_class->proxy_class != klass);
2632 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2633 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2636 mono_domain_unlock (domain);
2637 mono_loader_unlock ();
2642 * mono_object_get_virtual_method:
2643 * @obj: object to operate on.
2646 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2647 * the instance of a callvirt of method.
2650 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2653 MonoMethod **vtable;
2655 MonoMethod *res = NULL;
2657 klass = mono_object_class (obj);
2658 if (klass == mono_defaults.transparent_proxy_class) {
2659 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2665 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2668 mono_class_setup_vtable (klass);
2669 vtable = klass->vtable;
2671 if (method->slot == -1) {
2672 /* method->slot might not be set for instances of generic methods */
2673 if (method->is_inflated) {
2674 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2675 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2678 g_assert_not_reached ();
2682 /* check method->slot is a valid index: perform isinstance? */
2683 if (method->slot != -1) {
2684 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2686 gboolean variance_used = FALSE;
2687 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2688 g_assert (iface_offset > 0);
2689 res = vtable [iface_offset + method->slot];
2692 res = vtable [method->slot];
2697 /* It may be an interface, abstract class method or generic method */
2698 if (!res || mono_method_signature (res)->generic_param_count)
2701 /* generic methods demand invoke_with_check */
2702 if (mono_method_signature (res)->generic_param_count)
2703 res = mono_marshal_get_remoting_invoke_with_check (res);
2706 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2707 res = mono_cominterop_get_invoke (res);
2710 res = mono_marshal_get_remoting_invoke (res);
2713 if (method->is_inflated) {
2714 /* Have to inflate the result */
2715 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2725 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2727 g_error ("runtime invoke called on uninitialized runtime");
2731 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2734 * mono_runtime_invoke:
2735 * @method: method to invoke
2736 * @obJ: object instance
2737 * @params: arguments to the method
2738 * @exc: exception information.
2740 * Invokes the method represented by @method on the object @obj.
2742 * obj is the 'this' pointer, it should be NULL for static
2743 * methods, a MonoObject* for object instances and a pointer to
2744 * the value type for value types.
2746 * The params array contains the arguments to the method with the
2747 * same convention: MonoObject* pointers for object instances and
2748 * pointers to the value type otherwise.
2750 * From unmanaged code you'll usually use the
2751 * mono_runtime_invoke() variant.
2753 * Note that this function doesn't handle virtual methods for
2754 * you, it will exec the exact method you pass: we still need to
2755 * expose a function to lookup the derived class implementation
2756 * of a virtual method (there are examples of this in the code,
2759 * You can pass NULL as the exc argument if you don't want to
2760 * catch exceptions, otherwise, *exc will be set to the exception
2761 * thrown, if any. if an exception is thrown, you can't use the
2762 * MonoObject* result from the function.
2764 * If the method returns a value type, it is boxed in an object
2768 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2772 if (mono_runtime_get_no_exec ())
2773 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2775 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2776 mono_profiler_method_start_invoke (method);
2778 result = default_mono_runtime_invoke (method, obj, params, exc);
2780 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2781 mono_profiler_method_end_invoke (method);
2787 * mono_method_get_unmanaged_thunk:
2788 * @method: method to generate a thunk for.
2790 * Returns an unmanaged->managed thunk that can be used to call
2791 * a managed method directly from C.
2793 * The thunk's C signature closely matches the managed signature:
2795 * C#: public bool Equals (object obj);
2796 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2797 * MonoObject*, MonoException**);
2799 * The 1st ("this") parameter must not be used with static methods:
2801 * C#: public static bool ReferenceEquals (object a, object b);
2802 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2805 * The last argument must be a non-null pointer of a MonoException* pointer.
2806 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2807 * exception has been thrown in managed code. Otherwise it will point
2808 * to the MonoException* caught by the thunk. In this case, the result of
2809 * the thunk is undefined:
2811 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2812 * MonoException *ex = NULL;
2813 * Equals func = mono_method_get_unmanaged_thunk (method);
2814 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2816 * // handle exception
2819 * The calling convention of the thunk matches the platform's default
2820 * convention. This means that under Windows, C declarations must
2821 * contain the __stdcall attribute:
2823 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2824 * MonoObject*, MonoException**);
2828 * Value type arguments and return values are treated as they were objects:
2830 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2831 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2833 * Arguments must be properly boxed upon trunk's invocation, while return
2834 * values must be unboxed.
2837 mono_method_get_unmanaged_thunk (MonoMethod *method)
2839 method = mono_marshal_get_thunk_invoke_wrapper (method);
2840 return mono_compile_method (method);
2844 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2848 /* object fields cannot be byref, so we don't need a
2850 gpointer *p = (gpointer*)dest;
2857 case MONO_TYPE_BOOLEAN:
2859 case MONO_TYPE_U1: {
2860 guint8 *p = (guint8*)dest;
2861 *p = value ? *(guint8*)value : 0;
2866 case MONO_TYPE_CHAR: {
2867 guint16 *p = (guint16*)dest;
2868 *p = value ? *(guint16*)value : 0;
2871 #if SIZEOF_VOID_P == 4
2876 case MONO_TYPE_U4: {
2877 gint32 *p = (gint32*)dest;
2878 *p = value ? *(gint32*)value : 0;
2881 #if SIZEOF_VOID_P == 8
2886 case MONO_TYPE_U8: {
2887 gint64 *p = (gint64*)dest;
2888 *p = value ? *(gint64*)value : 0;
2891 case MONO_TYPE_R4: {
2892 float *p = (float*)dest;
2893 *p = value ? *(float*)value : 0;
2896 case MONO_TYPE_R8: {
2897 double *p = (double*)dest;
2898 *p = value ? *(double*)value : 0;
2901 case MONO_TYPE_STRING:
2902 case MONO_TYPE_SZARRAY:
2903 case MONO_TYPE_CLASS:
2904 case MONO_TYPE_OBJECT:
2905 case MONO_TYPE_ARRAY:
2906 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2908 case MONO_TYPE_FNPTR:
2909 case MONO_TYPE_PTR: {
2910 gpointer *p = (gpointer*)dest;
2911 *p = deref_pointer? *(gpointer*)value: value;
2914 case MONO_TYPE_VALUETYPE:
2915 /* note that 't' and 'type->type' can be different */
2916 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2917 t = mono_class_enum_basetype (type->data.klass)->type;
2920 MonoClass *class = mono_class_from_mono_type (type);
2921 int size = mono_class_value_size (class, NULL);
2923 mono_gc_bzero (dest, size);
2925 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2928 case MONO_TYPE_GENERICINST:
2929 t = type->data.generic_class->container_class->byval_arg.type;
2932 g_warning ("got type %x", type->type);
2933 g_assert_not_reached ();
2938 * mono_field_set_value:
2939 * @obj: Instance object
2940 * @field: MonoClassField describing the field to set
2941 * @value: The value to be set
2943 * Sets the value of the field described by @field in the object instance @obj
2944 * to the value passed in @value. This method should only be used for instance
2945 * fields. For static fields, use mono_field_static_set_value.
2947 * The value must be on the native format of the field type.
2950 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2954 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2956 dest = (char*)obj + field->offset;
2957 set_value (field->type, dest, value, FALSE);
2961 * mono_field_static_set_value:
2962 * @field: MonoClassField describing the field to set
2963 * @value: The value to be set
2965 * Sets the value of the static field described by @field
2966 * to the value passed in @value.
2968 * The value must be on the native format of the field type.
2971 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2975 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2976 /* you cant set a constant! */
2977 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2979 if (field->offset == -1) {
2980 /* Special static */
2983 mono_domain_lock (vt->domain);
2984 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2985 mono_domain_unlock (vt->domain);
2986 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2988 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2990 set_value (field->type, dest, value, FALSE);
2994 * mono_vtable_get_static_field_data:
2996 * Internal use function: return a pointer to the memory holding the static fields
2997 * for a class or NULL if there are no static fields.
2998 * This is exported only for use by the debugger.
3001 mono_vtable_get_static_field_data (MonoVTable *vt)
3003 if (!vt->has_static_fields)
3005 return vt->vtable [vt->klass->vtable_size];
3009 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3013 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3014 if (field->offset == -1) {
3015 /* Special static */
3018 mono_domain_lock (vt->domain);
3019 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3020 mono_domain_unlock (vt->domain);
3021 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3023 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3026 src = (guint8*)obj + field->offset;
3033 * mono_field_get_value:
3034 * @obj: Object instance
3035 * @field: MonoClassField describing the field to fetch information from
3036 * @value: pointer to the location where the value will be stored
3038 * Use this routine to get the value of the field @field in the object
3041 * The pointer provided by value must be of the field type, for reference
3042 * types this is a MonoObject*, for value types its the actual pointer to
3047 * mono_field_get_value (obj, int_field, &i);
3050 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3056 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3058 src = (char*)obj + field->offset;
3059 set_value (field->type, value, src, TRUE);
3063 * mono_field_get_value_object:
3064 * @domain: domain where the object will be created (if boxing)
3065 * @field: MonoClassField describing the field to fetch information from
3066 * @obj: The object instance for the field.
3068 * Returns: a new MonoObject with the value from the given field. If the
3069 * field represents a value type, the value is boxed.
3073 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3077 MonoVTable *vtable = NULL;
3079 gboolean is_static = FALSE;
3080 gboolean is_ref = FALSE;
3081 gboolean is_literal = FALSE;
3082 gboolean is_ptr = FALSE;
3084 MonoType *type = mono_field_get_type_checked (field, &error);
3086 if (!mono_error_ok (&error))
3087 mono_error_raise_exception (&error);
3089 switch (type->type) {
3090 case MONO_TYPE_STRING:
3091 case MONO_TYPE_OBJECT:
3092 case MONO_TYPE_CLASS:
3093 case MONO_TYPE_ARRAY:
3094 case MONO_TYPE_SZARRAY:
3099 case MONO_TYPE_BOOLEAN:
3102 case MONO_TYPE_CHAR:
3111 case MONO_TYPE_VALUETYPE:
3112 is_ref = type->byref;
3114 case MONO_TYPE_GENERICINST:
3115 is_ref = !mono_type_generic_inst_is_valuetype (type);
3121 g_error ("type 0x%x not handled in "
3122 "mono_field_get_value_object", type->type);
3126 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3129 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3133 vtable = mono_class_vtable (domain, field->parent);
3135 char *name = mono_type_get_full_name (field->parent);
3136 /*FIXME extend this to use the MonoError api*/
3137 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3141 if (!vtable->initialized)
3142 mono_runtime_class_init (vtable);
3150 get_default_field_value (domain, field, &o);
3151 } else if (is_static) {
3152 mono_field_static_get_value (vtable, field, &o);
3154 mono_field_get_value (obj, field, &o);
3160 static MonoMethod *m;
3166 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3167 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3173 get_default_field_value (domain, field, v);
3174 } else if (is_static) {
3175 mono_field_static_get_value (vtable, field, v);
3177 mono_field_get_value (obj, field, v);
3180 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3182 args [1] = mono_type_get_object (mono_domain_get (), type);
3184 return mono_runtime_invoke (m, NULL, args, NULL);
3187 /* boxed value type */
3188 klass = mono_class_from_mono_type (type);
3190 if (mono_class_is_nullable (klass))
3191 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3193 o = mono_object_new (domain, klass);
3194 v = ((gchar *) o) + sizeof (MonoObject);
3197 get_default_field_value (domain, field, v);
3198 } else if (is_static) {
3199 mono_field_static_get_value (vtable, field, v);
3201 mono_field_get_value (obj, field, v);
3208 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3211 const char *p = blob;
3212 mono_metadata_decode_blob_size (p, &p);
3215 case MONO_TYPE_BOOLEAN:
3218 *(guint8 *) value = *p;
3220 case MONO_TYPE_CHAR:
3223 *(guint16*) value = read16 (p);
3227 *(guint32*) value = read32 (p);
3231 *(guint64*) value = read64 (p);
3234 readr4 (p, (float*) value);
3237 readr8 (p, (double*) value);
3239 case MONO_TYPE_STRING:
3240 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3242 case MONO_TYPE_CLASS:
3243 *(gpointer*) value = NULL;
3247 g_warning ("type 0x%02x should not be in constant table", type);
3253 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3255 MonoTypeEnum def_type;
3258 data = mono_class_get_field_default_value (field, &def_type);
3259 mono_get_constant_value_from_blob (domain, def_type, data, value);
3263 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3267 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3269 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3270 get_default_field_value (vt->domain, field, value);
3274 if (field->offset == -1) {
3275 /* Special static */
3276 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3277 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3279 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3281 set_value (field->type, value, src, TRUE);
3285 * mono_field_static_get_value:
3286 * @vt: vtable to the object
3287 * @field: MonoClassField describing the field to fetch information from
3288 * @value: where the value is returned
3290 * Use this routine to get the value of the static field @field value.
3292 * The pointer provided by value must be of the field type, for reference
3293 * types this is a MonoObject*, for value types its the actual pointer to
3298 * mono_field_static_get_value (vt, int_field, &i);
3301 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3303 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3307 * mono_property_set_value:
3308 * @prop: MonoProperty to set
3309 * @obj: instance object on which to act
3310 * @params: parameters to pass to the propery
3311 * @exc: optional exception
3313 * Invokes the property's set method with the given arguments on the
3314 * object instance obj (or NULL for static properties).
3316 * You can pass NULL as the exc argument if you don't want to
3317 * catch exceptions, otherwise, *exc will be set to the exception
3318 * thrown, if any. if an exception is thrown, you can't use the
3319 * MonoObject* result from the function.
3322 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3324 default_mono_runtime_invoke (prop->set, obj, params, exc);
3328 * mono_property_get_value:
3329 * @prop: MonoProperty to fetch
3330 * @obj: instance object on which to act
3331 * @params: parameters to pass to the propery
3332 * @exc: optional exception
3334 * Invokes the property's get method with the given arguments on the
3335 * object instance obj (or NULL for static properties).
3337 * You can pass NULL as the exc argument if you don't want to
3338 * catch exceptions, otherwise, *exc will be set to the exception
3339 * thrown, if any. if an exception is thrown, you can't use the
3340 * MonoObject* result from the function.
3342 * Returns: the value from invoking the get method on the property.
3345 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3347 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3351 * mono_nullable_init:
3352 * @buf: The nullable structure to initialize.
3353 * @value: the value to initialize from
3354 * @klass: the type for the object
3356 * Initialize the nullable structure pointed to by @buf from @value which
3357 * should be a boxed value type. The size of @buf should be able to hold
3358 * as much data as the @klass->instance_size (which is the number of bytes
3359 * that will be copies).
3361 * Since Nullables have variable structure, we can not define a C
3362 * structure for them.
3365 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3367 MonoClass *param_class = klass->cast_class;
3369 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3370 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3372 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3374 if (param_class->has_references)
3375 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3377 mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3379 mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3384 * mono_nullable_box:
3385 * @buf: The buffer representing the data to be boxed
3386 * @klass: the type to box it as.
3388 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3392 mono_nullable_box (guint8 *buf, MonoClass *klass)
3394 MonoClass *param_class = klass->cast_class;
3396 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3397 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3399 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3400 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3401 if (param_class->has_references)
3402 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3404 mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3412 * mono_get_delegate_invoke:
3413 * @klass: The delegate class
3415 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3418 mono_get_delegate_invoke (MonoClass *klass)
3422 /* This is called at runtime, so avoid the slower search in metadata */
3423 mono_class_setup_methods (klass);
3424 if (klass->exception_type)
3426 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3431 * mono_runtime_delegate_invoke:
3432 * @delegate: pointer to a delegate object.
3433 * @params: parameters for the delegate.
3434 * @exc: Pointer to the exception result.
3436 * Invokes the delegate method @delegate with the parameters provided.
3438 * You can pass NULL as the exc argument if you don't want to
3439 * catch exceptions, otherwise, *exc will be set to the exception
3440 * thrown, if any. if an exception is thrown, you can't use the
3441 * MonoObject* result from the function.
3444 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3448 im = mono_get_delegate_invoke (delegate->vtable->klass);
3451 return mono_runtime_invoke (im, delegate, params, exc);
3454 static char **main_args = NULL;
3455 static int num_main_args;
3458 * mono_runtime_get_main_args:
3460 * Returns: a MonoArray with the arguments passed to the main program
3463 mono_runtime_get_main_args (void)
3467 MonoDomain *domain = mono_domain_get ();
3472 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3474 for (i = 0; i < num_main_args; ++i)
3475 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3481 free_main_args (void)
3485 for (i = 0; i < num_main_args; ++i)
3486 g_free (main_args [i]);
3491 * mono_runtime_run_main:
3492 * @method: the method to start the application with (usually Main)
3493 * @argc: number of arguments from the command line
3494 * @argv: array of strings from the command line
3495 * @exc: excetption results
3497 * Execute a standard Main() method (argc/argv contains the
3498 * executable name). This method also sets the command line argument value
3499 * needed by System.Environment.
3504 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3508 MonoArray *args = NULL;
3509 MonoDomain *domain = mono_domain_get ();
3510 gchar *utf8_fullpath;
3511 MonoMethodSignature *sig;
3513 g_assert (method != NULL);
3515 mono_thread_set_main (mono_thread_current ());
3517 main_args = g_new0 (char*, argc);
3518 num_main_args = argc;
3520 if (!g_path_is_absolute (argv [0])) {
3521 gchar *basename = g_path_get_basename (argv [0]);
3522 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3526 utf8_fullpath = mono_utf8_from_external (fullpath);
3527 if(utf8_fullpath == NULL) {
3528 /* Printing the arg text will cause glib to
3529 * whinge about "Invalid UTF-8", but at least
3530 * its relevant, and shows the problem text
3533 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3534 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3541 utf8_fullpath = mono_utf8_from_external (argv[0]);
3542 if(utf8_fullpath == NULL) {
3543 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3544 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3549 main_args [0] = utf8_fullpath;
3551 for (i = 1; i < argc; ++i) {
3554 utf8_arg=mono_utf8_from_external (argv[i]);
3555 if(utf8_arg==NULL) {
3556 /* Ditto the comment about Invalid UTF-8 here */
3557 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3558 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3562 main_args [i] = utf8_arg;
3567 sig = mono_method_signature (method);
3569 g_print ("Unable to load Main method.\n");
3573 if (sig->param_count) {
3574 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3575 for (i = 0; i < argc; ++i) {
3576 /* The encodings should all work, given that
3577 * we've checked all these args for the
3580 gchar *str = mono_utf8_from_external (argv [i]);
3581 MonoString *arg = mono_string_new (domain, str);
3582 mono_array_setref (args, i, arg);
3586 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3589 mono_assembly_set_main (method->klass->image->assembly);
3591 return mono_runtime_exec_main (method, args, exc);
3595 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3597 static MonoMethod *serialize_method;
3602 if (!serialize_method) {
3603 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3604 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3607 if (!serialize_method) {
3612 g_assert (!mono_object_class (obj)->marshalbyref);
3616 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3624 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3626 static MonoMethod *deserialize_method;
3631 if (!deserialize_method) {
3632 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3633 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3635 if (!deserialize_method) {
3642 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3650 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3652 static MonoMethod *get_proxy_method;
3654 MonoDomain *domain = mono_domain_get ();
3655 MonoRealProxy *real_proxy;
3656 MonoReflectionType *reflection_type;
3657 MonoTransparentProxy *transparent_proxy;
3659 if (!get_proxy_method)
3660 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3662 g_assert (obj->vtable->klass->marshalbyref);
3664 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3665 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3667 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3668 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3671 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3675 return (MonoObject*) transparent_proxy;
3679 * mono_object_xdomain_representation
3681 * @target_domain: a domain
3682 * @exc: pointer to a MonoObject*
3684 * Creates a representation of obj in the domain target_domain. This
3685 * is either a copy of obj arrived through via serialization and
3686 * deserialization or a proxy, depending on whether the object is
3687 * serializable or marshal by ref. obj must not be in target_domain.
3689 * If the object cannot be represented in target_domain, NULL is
3690 * returned and *exc is set to an appropriate exception.
3693 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3695 MonoObject *deserialized = NULL;
3696 gboolean failure = FALSE;
3700 if (mono_object_class (obj)->marshalbyref) {
3701 deserialized = make_transparent_proxy (obj, &failure, exc);
3703 MonoDomain *domain = mono_domain_get ();
3704 MonoObject *serialized;
3706 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3707 serialized = serialize_object (obj, &failure, exc);
3708 mono_domain_set_internal_with_options (target_domain, FALSE);
3710 deserialized = deserialize_object (serialized, &failure, exc);
3711 if (domain != target_domain)
3712 mono_domain_set_internal_with_options (domain, FALSE);
3715 return deserialized;
3718 /* Used in call_unhandled_exception_delegate */
3720 create_unhandled_exception_eventargs (MonoObject *exc)
3724 MonoMethod *method = NULL;
3725 MonoBoolean is_terminating = TRUE;
3728 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3731 mono_class_init (klass);
3733 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3734 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3738 args [1] = &is_terminating;
3740 obj = mono_object_new (mono_domain_get (), klass);
3741 mono_runtime_invoke (method, obj, args, NULL);
3746 /* Used in mono_unhandled_exception */
3748 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3749 MonoObject *e = NULL;
3751 MonoDomain *current_domain = mono_domain_get ();
3753 if (domain != current_domain)
3754 mono_domain_set_internal_with_options (domain, FALSE);
3756 g_assert (domain == mono_object_domain (domain->domain));
3758 if (mono_object_domain (exc) != domain) {
3759 MonoObject *serialization_exc;
3761 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3763 if (serialization_exc) {
3765 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3768 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3769 "System.Runtime.Serialization", "SerializationException",
3770 "Could not serialize unhandled exception.");
3774 g_assert (mono_object_domain (exc) == domain);
3776 pa [0] = domain->domain;
3777 pa [1] = create_unhandled_exception_eventargs (exc);
3778 mono_runtime_delegate_invoke (delegate, pa, &e);
3780 if (domain != current_domain)
3781 mono_domain_set_internal_with_options (current_domain, FALSE);
3785 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3786 if (!mono_error_ok (&error)) {
3787 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3788 mono_error_cleanup (&error);
3790 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3796 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3799 * mono_runtime_unhandled_exception_policy_set:
3800 * @policy: the new policy
3802 * This is a VM internal routine.
3804 * Sets the runtime policy for handling unhandled exceptions.
3807 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3808 runtime_unhandled_exception_policy = policy;
3812 * mono_runtime_unhandled_exception_policy_get:
3814 * This is a VM internal routine.
3816 * Gets the runtime policy for handling unhandled exceptions.
3818 MonoRuntimeUnhandledExceptionPolicy
3819 mono_runtime_unhandled_exception_policy_get (void) {
3820 return runtime_unhandled_exception_policy;
3824 * mono_unhandled_exception:
3825 * @exc: exception thrown
3827 * This is a VM internal routine.
3829 * We call this function when we detect an unhandled exception
3830 * in the default domain.
3832 * It invokes the * UnhandledException event in AppDomain or prints
3833 * a warning to the console
3836 mono_unhandled_exception (MonoObject *exc)
3838 MonoDomain *current_domain = mono_domain_get ();
3839 MonoDomain *root_domain = mono_get_root_domain ();
3840 MonoClassField *field;
3841 MonoObject *current_appdomain_delegate;
3842 MonoObject *root_appdomain_delegate;
3844 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3845 "UnhandledException");
3848 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3849 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3850 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3851 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3852 if (current_domain != root_domain) {
3853 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3855 current_appdomain_delegate = NULL;
3858 /* set exitcode only if we will abort the process */
3860 mono_environment_exitcode_set (1);
3861 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3862 mono_print_unhandled_exception (exc);
3864 if (root_appdomain_delegate) {
3865 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3867 if (current_appdomain_delegate) {
3868 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3875 * mono_runtime_exec_managed_code:
3876 * @domain: Application domain
3877 * @main_func: function to invoke from the execution thread
3878 * @main_args: parameter to the main_func
3880 * Launch a new thread to execute a function
3882 * main_func is called back from the thread with main_args as the
3883 * parameter. The callback function is expected to start Main()
3884 * eventually. This function then waits for all managed threads to
3886 * It is not necesseray anymore to execute managed code in a subthread,
3887 * so this function should not be used anymore by default: just
3888 * execute the code and then call mono_thread_manage ().
3891 mono_runtime_exec_managed_code (MonoDomain *domain,
3892 MonoMainThreadFunc main_func,
3895 mono_thread_create (domain, main_func, main_args);
3897 mono_thread_manage ();
3901 * Execute a standard Main() method (args doesn't contain the
3905 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3910 MonoCustomAttrInfo* cinfo;
3911 gboolean has_stathread_attribute;
3912 MonoInternalThread* thread = mono_thread_internal_current ();
3918 domain = mono_object_domain (args);
3919 if (!domain->entry_assembly) {
3921 MonoAssembly *assembly;
3923 assembly = method->klass->image->assembly;
3924 domain->entry_assembly = assembly;
3925 /* Domains created from another domain already have application_base and configuration_file set */
3926 if (domain->setup->application_base == NULL) {
3927 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3930 if (domain->setup->configuration_file == NULL) {
3931 str = g_strconcat (assembly->image->name, ".config", NULL);
3932 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3934 mono_set_private_bin_path_from_config (domain);
3938 cinfo = mono_custom_attrs_from_method (method);
3940 static MonoClass *stathread_attribute = NULL;
3941 if (!stathread_attribute)
3942 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3943 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3945 mono_custom_attrs_free (cinfo);
3947 has_stathread_attribute = FALSE;
3949 if (has_stathread_attribute) {
3950 thread->apartment_state = ThreadApartmentState_STA;
3952 thread->apartment_state = ThreadApartmentState_MTA;
3954 mono_thread_init_apartment_state ();
3956 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3958 /* FIXME: check signature of method */
3959 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3961 res = mono_runtime_invoke (method, NULL, pa, exc);
3963 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3967 mono_environment_exitcode_set (rval);
3969 mono_runtime_invoke (method, NULL, pa, exc);
3973 /* If the return type of Main is void, only
3974 * set the exitcode if an exception was thrown
3975 * (we don't want to blow away an
3976 * explicitly-set exit code)
3979 mono_environment_exitcode_set (rval);
3983 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3989 * mono_install_runtime_invoke:
3990 * @func: Function to install
3992 * This is a VM internal routine
3995 mono_install_runtime_invoke (MonoInvokeFunc func)
3997 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4002 * mono_runtime_invoke_array:
4003 * @method: method to invoke
4004 * @obJ: object instance
4005 * @params: arguments to the method
4006 * @exc: exception information.
4008 * Invokes the method represented by @method on the object @obj.
4010 * obj is the 'this' pointer, it should be NULL for static
4011 * methods, a MonoObject* for object instances and a pointer to
4012 * the value type for value types.
4014 * The params array contains the arguments to the method with the
4015 * same convention: MonoObject* pointers for object instances and
4016 * pointers to the value type otherwise. The _invoke_array
4017 * variant takes a C# object[] as the params argument (MonoArray
4018 * *params): in this case the value types are boxed inside the
4019 * respective reference representation.
4021 * From unmanaged code you'll usually use the
4022 * mono_runtime_invoke() variant.
4024 * Note that this function doesn't handle virtual methods for
4025 * you, it will exec the exact method you pass: we still need to
4026 * expose a function to lookup the derived class implementation
4027 * of a virtual method (there are examples of this in the code,
4030 * You can pass NULL as the exc argument if you don't want to
4031 * catch exceptions, otherwise, *exc will be set to the exception
4032 * thrown, if any. if an exception is thrown, you can't use the
4033 * MonoObject* result from the function.
4035 * If the method returns a value type, it is boxed in an object
4039 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4042 MonoMethodSignature *sig = mono_method_signature (method);
4043 gpointer *pa = NULL;
4046 gboolean has_byref_nullables = FALSE;
4048 if (NULL != params) {
4049 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4050 for (i = 0; i < mono_array_length (params); i++) {
4051 MonoType *t = sig->params [i];
4057 case MONO_TYPE_BOOLEAN:
4060 case MONO_TYPE_CHAR:
4069 case MONO_TYPE_VALUETYPE:
4070 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4071 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4072 pa [i] = mono_array_get (params, MonoObject*, i);
4074 has_byref_nullables = TRUE;
4076 /* MS seems to create the objects if a null is passed in */
4077 if (!mono_array_get (params, MonoObject*, i))
4078 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4082 * We can't pass the unboxed vtype byref to the callee, since
4083 * that would mean the callee would be able to modify boxed
4084 * primitive types. So we (and MS) make a copy of the boxed
4085 * object, pass that to the callee, and replace the original
4086 * boxed object in the arg array with the copy.
4088 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4089 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4090 mono_array_setref (params, i, copy);
4093 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4096 case MONO_TYPE_STRING:
4097 case MONO_TYPE_OBJECT:
4098 case MONO_TYPE_CLASS:
4099 case MONO_TYPE_ARRAY:
4100 case MONO_TYPE_SZARRAY:
4102 pa [i] = mono_array_addr (params, MonoObject*, i);
4103 // FIXME: I need to check this code path
4105 pa [i] = mono_array_get (params, MonoObject*, i);
4107 case MONO_TYPE_GENERICINST:
4109 t = &t->data.generic_class->container_class->this_arg;
4111 t = &t->data.generic_class->container_class->byval_arg;
4113 case MONO_TYPE_PTR: {
4116 /* The argument should be an IntPtr */
4117 arg = mono_array_get (params, MonoObject*, i);
4121 g_assert (arg->vtable->klass == mono_defaults.int_class);
4122 pa [i] = ((MonoIntPtr*)arg)->m_value;
4127 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4132 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4135 if (mono_class_is_nullable (method->klass)) {
4136 /* Need to create a boxed vtype instead */
4142 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4146 obj = mono_object_new (mono_domain_get (), method->klass);
4147 g_assert (obj); /*maybe we should raise a TLE instead?*/
4148 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4149 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4151 if (method->klass->valuetype)
4152 o = mono_object_unbox (obj);
4155 } else if (method->klass->valuetype) {
4156 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4159 mono_runtime_invoke (method, o, pa, exc);
4162 if (mono_class_is_nullable (method->klass)) {
4163 MonoObject *nullable;
4165 /* Convert the unboxed vtype into a Nullable structure */
4166 nullable = mono_object_new (mono_domain_get (), method->klass);
4168 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4169 obj = mono_object_unbox (nullable);
4172 /* obj must be already unboxed if needed */
4173 res = mono_runtime_invoke (method, obj, pa, exc);
4175 if (sig->ret->type == MONO_TYPE_PTR) {
4176 MonoClass *pointer_class;
4177 static MonoMethod *box_method;
4179 MonoObject *box_exc;
4182 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4183 * convert it to a Pointer object.
4185 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4187 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4189 g_assert (res->vtable->klass == mono_defaults.int_class);
4190 box_args [0] = ((MonoIntPtr*)res)->m_value;
4191 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4192 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4193 g_assert (!box_exc);
4196 if (has_byref_nullables) {
4198 * The runtime invoke wrapper already converted byref nullables back,
4199 * and stored them in pa, we just need to copy them back to the
4202 for (i = 0; i < mono_array_length (params); i++) {
4203 MonoType *t = sig->params [i];
4205 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4206 mono_array_setref (params, i, pa [i]);
4215 arith_overflow (void)
4217 mono_raise_exception (mono_get_exception_overflow ());
4221 * mono_object_allocate:
4222 * @size: number of bytes to allocate
4224 * This is a very simplistic routine until we have our GC-aware
4227 * Returns: an allocated object of size @size, or NULL on failure.
4229 static inline void *
4230 mono_object_allocate (size_t size, MonoVTable *vtable)
4233 mono_stats.new_object_count++;
4234 ALLOC_OBJECT (o, vtable, size);
4240 * mono_object_allocate_ptrfree:
4241 * @size: number of bytes to allocate
4243 * Note that the memory allocated is not zeroed.
4244 * Returns: an allocated object of size @size, or NULL on failure.
4246 static inline void *
4247 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4250 mono_stats.new_object_count++;
4251 ALLOC_PTRFREE (o, vtable, size);
4255 static inline void *
4256 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4259 ALLOC_TYPED (o, size, vtable);
4260 mono_stats.new_object_count++;
4267 * @klass: the class of the object that we want to create
4269 * Returns: a newly created object whose definition is
4270 * looked up using @klass. This will not invoke any constructors,
4271 * so the consumer of this routine has to invoke any constructors on
4272 * its own to initialize the object.
4274 * It returns NULL on failure.
4277 mono_object_new (MonoDomain *domain, MonoClass *klass)
4281 MONO_ARCH_SAVE_REGS;
4282 vtable = mono_class_vtable (domain, klass);
4285 return mono_object_new_specific (vtable);
4289 * mono_object_new_pinned:
4291 * Same as mono_object_new, but the returned object will be pinned.
4292 * For SGEN, these objects will only be freed at appdomain unload.
4295 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4299 MONO_ARCH_SAVE_REGS;
4300 vtable = mono_class_vtable (domain, klass);
4305 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4307 return mono_object_new_specific (vtable);
4312 * mono_object_new_specific:
4313 * @vtable: the vtable of the object that we want to create
4315 * Returns: A newly created object with class and domain specified
4319 mono_object_new_specific (MonoVTable *vtable)
4323 MONO_ARCH_SAVE_REGS;
4325 /* check for is_com_object for COM Interop */
4326 if (vtable->remote || vtable->klass->is_com_object)
4329 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4332 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4335 mono_class_init (klass);
4337 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4339 vtable->domain->create_proxy_for_type_method = im;
4342 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4344 o = mono_runtime_invoke (im, NULL, pa, NULL);
4345 if (o != NULL) return o;
4348 return mono_object_new_alloc_specific (vtable);
4352 mono_object_new_alloc_specific (MonoVTable *vtable)
4356 if (!vtable->klass->has_references) {
4357 o = mono_object_new_ptrfree (vtable);
4358 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4359 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4361 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4362 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4364 if (G_UNLIKELY (vtable->klass->has_finalize))
4365 mono_object_register_finalizer (o);
4367 if (G_UNLIKELY (profile_allocs))
4368 mono_profiler_allocation (o, vtable->klass);
4373 mono_object_new_fast (MonoVTable *vtable)
4376 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4381 mono_object_new_ptrfree (MonoVTable *vtable)
4384 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4385 #if NEED_TO_ZERO_PTRFREE
4386 /* an inline memset is much faster for the common vcase of small objects
4387 * note we assume the allocated size is a multiple of sizeof (void*).
4389 if (vtable->klass->instance_size < 128) {
4391 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4392 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4398 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4405 mono_object_new_ptrfree_box (MonoVTable *vtable)
4408 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4409 /* the object will be boxed right away, no need to memzero it */
4414 * mono_class_get_allocation_ftn:
4416 * @for_box: the object will be used for boxing
4417 * @pass_size_in_words:
4419 * Return the allocation function appropriate for the given class.
4423 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4425 *pass_size_in_words = FALSE;
4427 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4428 profile_allocs = FALSE;
4430 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4431 return mono_object_new_specific;
4433 if (!vtable->klass->has_references) {
4434 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4436 return mono_object_new_ptrfree_box;
4437 return mono_object_new_ptrfree;
4440 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4442 return mono_object_new_fast;
4445 * FIXME: This is actually slower than mono_object_new_fast, because
4446 * of the overhead of parameter passing.
4449 *pass_size_in_words = TRUE;
4450 #ifdef GC_REDIRECT_TO_LOCAL
4451 return GC_local_gcj_fast_malloc;
4453 return GC_gcj_fast_malloc;
4458 return mono_object_new_specific;
4462 * mono_object_new_from_token:
4463 * @image: Context where the type_token is hosted
4464 * @token: a token of the type that we want to create
4466 * Returns: A newly created object whose definition is
4467 * looked up using @token in the @image image
4470 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4474 class = mono_class_get (image, token);
4476 return mono_object_new (domain, class);
4481 * mono_object_clone:
4482 * @obj: the object to clone
4484 * Returns: A newly created object who is a shallow copy of @obj
4487 mono_object_clone (MonoObject *obj)
4490 int size = obj->vtable->klass->instance_size;
4492 if (obj->vtable->klass->rank)
4493 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4495 o = mono_object_allocate (size, obj->vtable);
4497 if (obj->vtable->klass->has_references) {
4498 mono_gc_wbarrier_object_copy (o, obj);
4500 int size = obj->vtable->klass->instance_size;
4501 /* do not copy the sync state */
4502 mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4504 if (G_UNLIKELY (profile_allocs))
4505 mono_profiler_allocation (o, obj->vtable->klass);
4507 if (obj->vtable->klass->has_finalize)
4508 mono_object_register_finalizer (o);
4513 * mono_array_full_copy:
4514 * @src: source array to copy
4515 * @dest: destination array
4517 * Copies the content of one array to another with exactly the same type and size.
4520 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4523 MonoClass *klass = src->obj.vtable->klass;
4525 MONO_ARCH_SAVE_REGS;
4527 g_assert (klass == dest->obj.vtable->klass);
4529 size = mono_array_length (src);
4530 g_assert (size == mono_array_length (dest));
4531 size *= mono_array_element_size (klass);
4533 if (klass->element_class->valuetype) {
4534 if (klass->element_class->has_references)
4535 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4537 mono_gc_memmove (&dest->vector, &src->vector, size);
4539 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4542 mono_gc_memmove (&dest->vector, &src->vector, size);
4547 * mono_array_clone_in_domain:
4548 * @domain: the domain in which the array will be cloned into
4549 * @array: the array to clone
4551 * This routine returns a copy of the array that is hosted on the
4552 * specified MonoDomain.
4555 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4560 MonoClass *klass = array->obj.vtable->klass;
4562 MONO_ARCH_SAVE_REGS;
4564 if (array->bounds == NULL) {
4565 size = mono_array_length (array);
4566 o = mono_array_new_full (domain, klass, &size, NULL);
4568 size *= mono_array_element_size (klass);
4570 if (klass->element_class->valuetype) {
4571 if (klass->element_class->has_references)
4572 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4574 mono_gc_memmove (&o->vector, &array->vector, size);
4576 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4579 mono_gc_memmove (&o->vector, &array->vector, size);
4584 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4585 size = mono_array_element_size (klass);
4586 for (i = 0; i < klass->rank; ++i) {
4587 sizes [i] = array->bounds [i].length;
4588 size *= array->bounds [i].length;
4589 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4591 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4593 if (klass->element_class->valuetype) {
4594 if (klass->element_class->has_references)
4595 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4597 mono_gc_memmove (&o->vector, &array->vector, size);
4599 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4602 mono_gc_memmove (&o->vector, &array->vector, size);
4610 * @array: the array to clone
4612 * Returns: A newly created array who is a shallow copy of @array
4615 mono_array_clone (MonoArray *array)
4617 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4620 /* helper macros to check for overflow when calculating the size of arrays */
4621 #ifdef MONO_BIG_ARRAYS
4622 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4623 #define MYGUINT_MAX MYGUINT64_MAX
4624 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4625 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4626 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4627 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4628 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4630 #define MYGUINT32_MAX 4294967295U
4631 #define MYGUINT_MAX MYGUINT32_MAX
4632 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4633 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4634 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4635 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4636 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4640 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4644 byte_len = mono_array_element_size (class);
4645 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4648 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4650 byte_len += sizeof (MonoArray);
4658 * mono_array_new_full:
4659 * @domain: domain where the object is created
4660 * @array_class: array class
4661 * @lengths: lengths for each dimension in the array
4662 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4664 * This routine creates a new array objects with the given dimensions,
4665 * lower bounds and type.
4668 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4670 uintptr_t byte_len, len, bounds_size;
4673 MonoArrayBounds *bounds;
4677 if (!array_class->inited)
4678 mono_class_init (array_class);
4682 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4683 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4685 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4689 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4691 for (i = 0; i < array_class->rank; ++i) {
4692 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4694 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4695 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4700 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4701 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4705 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4706 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4707 byte_len = (byte_len + 3) & ~3;
4708 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4709 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4710 byte_len += bounds_size;
4713 * Following three lines almost taken from mono_object_new ():
4714 * they need to be kept in sync.
4716 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4717 #ifndef HAVE_SGEN_GC
4718 if (!array_class->has_references) {
4719 o = mono_object_allocate_ptrfree (byte_len, vtable);
4720 #if NEED_TO_ZERO_PTRFREE
4721 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4723 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4724 o = mono_object_allocate_spec (byte_len, vtable);
4726 o = mono_object_allocate (byte_len, vtable);
4729 array = (MonoArray*)o;
4730 array->max_length = len;
4733 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4734 array->bounds = bounds;
4738 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4740 o = mono_gc_alloc_vector (vtable, byte_len, len);
4741 array = (MonoArray*)o;
4742 mono_stats.new_object_count++;
4744 bounds = array->bounds;
4748 for (i = 0; i < array_class->rank; ++i) {
4749 bounds [i].length = lengths [i];
4751 bounds [i].lower_bound = lower_bounds [i];
4755 if (G_UNLIKELY (profile_allocs))
4756 mono_profiler_allocation (o, array_class);
4763 * @domain: domain where the object is created
4764 * @eclass: element class
4765 * @n: number of array elements
4767 * This routine creates a new szarray with @n elements of type @eclass.
4770 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4774 MONO_ARCH_SAVE_REGS;
4776 ac = mono_array_class_get (eclass, 1);
4779 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4783 * mono_array_new_specific:
4784 * @vtable: a vtable in the appropriate domain for an initialized class
4785 * @n: number of array elements
4787 * This routine is a fast alternative to mono_array_new() for code which
4788 * can be sure about the domain it operates in.
4791 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4797 MONO_ARCH_SAVE_REGS;
4799 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4804 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4805 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4808 #ifndef HAVE_SGEN_GC
4809 if (!vtable->klass->has_references) {
4810 o = mono_object_allocate_ptrfree (byte_len, vtable);
4811 #if NEED_TO_ZERO_PTRFREE
4812 ((MonoArray*)o)->bounds = NULL;
4813 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4815 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4816 o = mono_object_allocate_spec (byte_len, vtable);
4818 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4819 o = mono_object_allocate (byte_len, vtable);
4822 ao = (MonoArray *)o;
4825 o = mono_gc_alloc_vector (vtable, byte_len, n);
4827 mono_stats.new_object_count++;
4830 if (G_UNLIKELY (profile_allocs))
4831 mono_profiler_allocation (o, vtable->klass);
4837 * mono_string_new_utf16:
4838 * @text: a pointer to an utf16 string
4839 * @len: the length of the string
4841 * Returns: A newly created string object which contains @text.
4844 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4848 s = mono_string_new_size (domain, len);
4849 g_assert (s != NULL);
4851 memcpy (mono_string_chars (s), text, len * 2);
4857 * mono_string_new_size:
4858 * @text: a pointer to an utf16 string
4859 * @len: the length of the string
4861 * Returns: A newly created string object of @len
4864 mono_string_new_size (MonoDomain *domain, gint32 len)
4868 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4870 /* overflow ? can't fit it, can't allocate it! */
4872 mono_gc_out_of_memory (-1);
4874 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4877 #ifndef HAVE_SGEN_GC
4878 s = mono_object_allocate_ptrfree (size, vtable);
4882 s = mono_gc_alloc_string (vtable, size, len);
4884 #if NEED_TO_ZERO_PTRFREE
4887 if (G_UNLIKELY (profile_allocs))
4888 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4894 * mono_string_new_len:
4895 * @text: a pointer to an utf8 string
4896 * @length: number of bytes in @text to consider
4898 * Returns: A newly created string object which contains @text.
4901 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4903 GError *error = NULL;
4904 MonoString *o = NULL;
4906 glong items_written;
4908 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4911 o = mono_string_new_utf16 (domain, ut, items_written);
4913 g_error_free (error);
4922 * @text: a pointer to an utf8 string
4924 * Returns: A newly created string object which contains @text.
4927 mono_string_new (MonoDomain *domain, const char *text)
4929 GError *error = NULL;
4930 MonoString *o = NULL;
4932 glong items_written;
4937 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4940 o = mono_string_new_utf16 (domain, ut, items_written);
4942 g_error_free (error);
4945 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4950 MonoString *o = NULL;
4952 if (!g_utf8_validate (text, -1, &end))
4955 len = g_utf8_strlen (text, -1);
4956 o = mono_string_new_size (domain, len);
4957 str = mono_string_chars (o);
4959 while (text < end) {
4960 *str++ = g_utf8_get_char (text);
4961 text = g_utf8_next_char (text);
4968 * mono_string_new_wrapper:
4969 * @text: pointer to utf8 characters.
4971 * Helper function to create a string object from @text in the current domain.
4974 mono_string_new_wrapper (const char *text)
4976 MonoDomain *domain = mono_domain_get ();
4978 MONO_ARCH_SAVE_REGS;
4981 return mono_string_new (domain, text);
4988 * @class: the class of the value
4989 * @value: a pointer to the unboxed data
4991 * Returns: A newly created object which contains @value.
4994 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5000 g_assert (class->valuetype);
5001 if (mono_class_is_nullable (class))
5002 return mono_nullable_box (value, class);
5004 vtable = mono_class_vtable (domain, class);
5007 size = mono_class_instance_size (class);
5008 res = mono_object_new_alloc_specific (vtable);
5009 if (G_UNLIKELY (profile_allocs))
5010 mono_profiler_allocation (res, class);
5012 size = size - sizeof (MonoObject);
5015 g_assert (size == mono_class_value_size (class, NULL));
5016 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5018 #if NO_UNALIGNED_ACCESS
5019 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5023 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5026 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5029 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5032 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5035 mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
5039 if (class->has_finalize)
5040 mono_object_register_finalizer (res);
5046 * @dest: destination pointer
5047 * @src: source pointer
5048 * @klass: a valuetype class
5050 * Copy a valuetype from @src to @dest. This function must be used
5051 * when @klass contains references fields.
5054 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5056 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5060 * mono_value_copy_array:
5061 * @dest: destination array
5062 * @dest_idx: index in the @dest array
5063 * @src: source pointer
5064 * @count: number of items
5066 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5067 * This function must be used when @klass contains references fields.
5068 * Overlap is handled.
5071 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5073 int size = mono_array_element_size (dest->obj.vtable->klass);
5074 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5075 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5076 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5080 * mono_object_get_domain:
5081 * @obj: object to query
5083 * Returns: the MonoDomain where the object is hosted
5086 mono_object_get_domain (MonoObject *obj)
5088 return mono_object_domain (obj);
5092 * mono_object_get_class:
5093 * @obj: object to query
5095 * Returns: the MonOClass of the object.
5098 mono_object_get_class (MonoObject *obj)
5100 return mono_object_class (obj);
5103 * mono_object_get_size:
5104 * @o: object to query
5106 * Returns: the size, in bytes, of @o
5109 mono_object_get_size (MonoObject* o)
5111 MonoClass* klass = mono_object_class (o);
5112 if (klass == mono_defaults.string_class) {
5113 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5114 } else if (o->vtable->rank) {
5115 MonoArray *array = (MonoArray*)o;
5116 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5117 if (array->bounds) {
5120 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5124 return mono_class_instance_size (klass);
5129 * mono_object_unbox:
5130 * @obj: object to unbox
5132 * Returns: a pointer to the start of the valuetype boxed in this
5135 * This method will assert if the object passed is not a valuetype.
5138 mono_object_unbox (MonoObject *obj)
5140 /* add assert for valuetypes? */
5141 g_assert (obj->vtable->klass->valuetype);
5142 return ((char*)obj) + sizeof (MonoObject);
5146 * mono_object_isinst:
5148 * @klass: a pointer to a class
5150 * Returns: @obj if @obj is derived from @klass
5153 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5156 mono_class_init (klass);
5158 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5159 return mono_object_isinst_mbyref (obj, klass);
5164 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5168 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5177 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5178 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5182 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5183 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5186 MonoClass *oklass = vt->klass;
5187 if ((oklass == mono_defaults.transparent_proxy_class))
5188 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5190 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5194 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5196 MonoDomain *domain = mono_domain_get ();
5198 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5199 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5200 MonoMethod *im = NULL;
5203 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5204 im = mono_object_get_virtual_method (rp, im);
5207 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5210 res = mono_runtime_invoke (im, rp, pa, NULL);
5212 if (*(MonoBoolean *) mono_object_unbox(res)) {
5213 /* Update the vtable of the remote type, so it can safely cast to this new type */
5214 mono_upgrade_remote_class (domain, obj, klass);
5223 * mono_object_castclass_mbyref:
5225 * @klass: a pointer to a class
5227 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5230 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5232 if (!obj) return NULL;
5233 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5235 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5237 "InvalidCastException"));
5242 MonoDomain *orig_domain;
5248 str_lookup (MonoDomain *domain, gpointer user_data)
5250 LDStrInfo *info = user_data;
5251 if (info->res || domain == info->orig_domain)
5253 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5259 mono_string_get_pinned (MonoString *str)
5263 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5264 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5266 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5267 news->length = mono_string_length (str);
5273 #define mono_string_get_pinned(str) (str)
5277 mono_string_is_interned_lookup (MonoString *str, int insert)
5279 MonoGHashTable *ldstr_table;
5283 domain = ((MonoObject *)str)->vtable->domain;
5284 ldstr_table = domain->ldstr_table;
5286 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5291 str = mono_string_get_pinned (str);
5293 mono_g_hash_table_insert (ldstr_table, str, str);
5297 LDStrInfo ldstr_info;
5298 ldstr_info.orig_domain = domain;
5299 ldstr_info.ins = str;
5300 ldstr_info.res = NULL;
5302 mono_domain_foreach (str_lookup, &ldstr_info);
5303 if (ldstr_info.res) {
5305 * the string was already interned in some other domain:
5306 * intern it in the current one as well.
5308 mono_g_hash_table_insert (ldstr_table, str, str);
5318 * mono_string_is_interned:
5319 * @o: String to probe
5321 * Returns whether the string has been interned.
5324 mono_string_is_interned (MonoString *o)
5326 return mono_string_is_interned_lookup (o, FALSE);
5330 * mono_string_intern:
5331 * @o: String to intern
5333 * Interns the string passed.
5334 * Returns: The interned string.
5337 mono_string_intern (MonoString *str)
5339 return mono_string_is_interned_lookup (str, TRUE);
5344 * @domain: the domain where the string will be used.
5345 * @image: a metadata context
5346 * @idx: index into the user string table.
5348 * Implementation for the ldstr opcode.
5349 * Returns: a loaded string from the @image/@idx combination.
5352 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5354 MONO_ARCH_SAVE_REGS;
5356 if (image->dynamic) {
5357 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5360 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5361 return NULL; /*FIXME we should probably be raising an exception here*/
5362 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5367 * mono_ldstr_metadata_sig
5368 * @domain: the domain for the string
5369 * @sig: the signature of a metadata string
5371 * Returns: a MonoString for a string stored in the metadata
5374 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5376 const char *str = sig;
5377 MonoString *o, *interned;
5380 len2 = mono_metadata_decode_blob_size (str, &str);
5383 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5384 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5387 guint16 *p2 = (guint16*)mono_string_chars (o);
5388 for (i = 0; i < len2; ++i) {
5389 *p2 = GUINT16_FROM_LE (*p2);
5395 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5397 /* o will get garbage collected */
5401 o = mono_string_get_pinned (o);
5403 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5410 * mono_string_to_utf8:
5411 * @s: a System.String
5413 * Returns the UTF8 representation for @s.
5414 * The resulting buffer needs to be freed with mono_free().
5416 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5419 mono_string_to_utf8 (MonoString *s)
5422 char *result = mono_string_to_utf8_checked (s, &error);
5424 if (!mono_error_ok (&error))
5425 mono_error_raise_exception (&error);
5430 * mono_string_to_utf8_checked:
5431 * @s: a System.String
5432 * @error: a MonoError.
5434 * Converts a MonoString to its UTF8 representation. May fail; check
5435 * @error to determine whether the conversion was successful.
5436 * The resulting buffer should be freed with mono_free().
5439 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5443 GError *gerror = NULL;
5445 mono_error_init (error);
5451 return g_strdup ("");
5453 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5455 mono_error_set_argument (error, "string", "%s", gerror->message);
5456 g_error_free (gerror);
5459 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5460 if (s->length > written) {
5461 /* allocate the total length and copy the part of the string that has been converted */
5462 char *as2 = g_malloc0 (s->length);
5463 memcpy (as2, as, written);
5472 * mono_string_to_utf8_ignore:
5475 * Converts a MonoString to its UTF8 representation. Will ignore
5476 * invalid surrogate pairs.
5477 * The resulting buffer should be freed with mono_free().
5481 mono_string_to_utf8_ignore (MonoString *s)
5490 return g_strdup ("");
5492 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5494 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5495 if (s->length > written) {
5496 /* allocate the total length and copy the part of the string that has been converted */
5497 char *as2 = g_malloc0 (s->length);
5498 memcpy (as2, as, written);
5507 * mono_string_to_utf8_image_ignore:
5508 * @s: a System.String
5510 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5513 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5515 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5519 * mono_string_to_utf8_mp_ignore:
5520 * @s: a System.String
5522 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5525 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5527 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5532 * mono_string_to_utf16:
5535 * Return an null-terminated array of the utf-16 chars
5536 * contained in @s. The result must be freed with g_free().
5537 * This is a temporary helper until our string implementation
5538 * is reworked to always include the null terminating char.
5541 mono_string_to_utf16 (MonoString *s)
5548 as = g_malloc ((s->length * 2) + 2);
5549 as [(s->length * 2)] = '\0';
5550 as [(s->length * 2) + 1] = '\0';
5553 return (gunichar2 *)(as);
5556 memcpy (as, mono_string_chars(s), s->length * 2);
5557 return (gunichar2 *)(as);
5561 * mono_string_from_utf16:
5562 * @data: the UTF16 string (LPWSTR) to convert
5564 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5566 * Returns: a MonoString.
5569 mono_string_from_utf16 (gunichar2 *data)
5571 MonoDomain *domain = mono_domain_get ();
5577 while (data [len]) len++;
5579 return mono_string_new_utf16 (domain, data, len);
5584 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5591 r = mono_string_to_utf8_ignore (s);
5593 r = mono_string_to_utf8_checked (s, error);
5594 if (!mono_error_ok (error))
5601 len = strlen (r) + 1;
5603 mp_s = mono_mempool_alloc (mp, len);
5605 mp_s = mono_image_alloc (image, len);
5607 memcpy (mp_s, r, len);
5615 * mono_string_to_utf8_image:
5616 * @s: a System.String
5618 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5621 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5623 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5627 * mono_string_to_utf8_mp:
5628 * @s: a System.String
5630 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5633 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5635 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5639 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5642 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5644 eh_callbacks = *cbs;
5647 MonoRuntimeExceptionHandlingCallbacks *
5648 mono_get_eh_callbacks (void)
5650 return &eh_callbacks;
5654 * mono_raise_exception:
5655 * @ex: exception object
5657 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5660 mono_raise_exception (MonoException *ex)
5663 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5664 * that will cause gcc to omit the function epilog, causing problems when
5665 * the JIT tries to walk the stack, since the return address on the stack
5666 * will point into the next function in the executable, not this one.
5669 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5670 MonoInternalThread *thread = mono_thread_internal_current ();
5671 g_assert (ex->object.vtable->domain == mono_domain_get ());
5672 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5675 eh_callbacks.mono_raise_exception (ex);
5679 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5681 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5682 MonoInternalThread *thread = mono_thread_internal_current ();
5683 g_assert (ex->object.vtable->domain == mono_domain_get ());
5684 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5687 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5691 * mono_wait_handle_new:
5692 * @domain: Domain where the object will be created
5693 * @handle: Handle for the wait handle
5695 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5698 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5700 MonoWaitHandle *res;
5701 gpointer params [1];
5702 static MonoMethod *handle_set;
5704 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5706 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5708 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5710 params [0] = &handle;
5711 mono_runtime_invoke (handle_set, res, params, NULL);
5717 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5719 static MonoClassField *f_os_handle;
5720 static MonoClassField *f_safe_handle;
5722 if (!f_os_handle && !f_safe_handle) {
5723 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5724 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5729 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5733 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5740 mono_runtime_capture_context (MonoDomain *domain)
5742 RuntimeInvokeFunction runtime_invoke;
5744 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5745 MonoMethod *method = mono_get_context_capture_method ();
5746 MonoMethod *wrapper;
5749 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5750 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5751 domain->capture_context_method = mono_compile_method (method);
5754 runtime_invoke = domain->capture_context_runtime_invoke;
5756 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5759 * mono_async_result_new:
5760 * @domain:domain where the object will be created.
5761 * @handle: wait handle.
5762 * @state: state to pass to AsyncResult
5763 * @data: C closure data.
5765 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5766 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5770 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5772 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5773 MonoObject *context = mono_runtime_capture_context (domain);
5774 /* we must capture the execution context from the original thread */
5776 MONO_OBJECT_SETREF (res, execution_context, context);
5777 /* note: result may be null if the flow is suppressed */
5781 MONO_OBJECT_SETREF (res, object_data, object_data);
5782 MONO_OBJECT_SETREF (res, async_state, state);
5784 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5786 res->sync_completed = FALSE;
5787 res->completed = FALSE;
5793 mono_message_init (MonoDomain *domain,
5794 MonoMethodMessage *this,
5795 MonoReflectionMethod *method,
5796 MonoArray *out_args)
5798 static MonoClass *object_array_klass;
5799 static MonoClass *byte_array_klass;
5800 static MonoClass *string_array_klass;
5801 MonoMethodSignature *sig = mono_method_signature (method->method);
5807 if (!object_array_klass) {
5810 klass = mono_array_class_get (mono_defaults.object_class, 1);
5813 mono_memory_barrier ();
5814 object_array_klass = klass;
5816 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5819 mono_memory_barrier ();
5820 byte_array_klass = klass;
5822 klass = mono_array_class_get (mono_defaults.string_class, 1);
5825 mono_memory_barrier ();
5826 string_array_klass = klass;
5829 MONO_OBJECT_SETREF (this, method, method);
5831 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5832 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5833 this->async_result = NULL;
5834 this->call_type = CallType_Sync;
5836 names = g_new (char *, sig->param_count);
5837 mono_method_get_param_names (method->method, (const char **) names);
5838 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5840 for (i = 0; i < sig->param_count; i++) {
5841 name = mono_string_new (domain, names [i]);
5842 mono_array_setref (this->names, i, name);
5846 for (i = 0, j = 0; i < sig->param_count; i++) {
5847 if (sig->params [i]->byref) {
5849 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5850 mono_array_setref (this->args, i, arg);
5854 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5858 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5861 mono_array_set (this->arg_types, guint8, i, arg_type);
5866 * mono_remoting_invoke:
5867 * @real_proxy: pointer to a RealProxy object
5868 * @msg: The MonoMethodMessage to execute
5869 * @exc: used to store exceptions
5870 * @out_args: used to store output arguments
5872 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5873 * IMessage interface and it is not trivial to extract results from there. So
5874 * we call an helper method PrivateInvoke instead of calling
5875 * RealProxy::Invoke() directly.
5877 * Returns: the result object.
5880 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5881 MonoObject **exc, MonoArray **out_args)
5883 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5886 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5889 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5891 real_proxy->vtable->domain->private_invoke_method = im;
5894 pa [0] = real_proxy;
5899 return mono_runtime_invoke (im, NULL, pa, exc);
5903 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5904 MonoObject **exc, MonoArray **out_args)
5906 static MonoClass *object_array_klass;
5909 MonoMethodSignature *sig;
5911 int i, j, outarg_count = 0;
5913 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5915 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5916 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5917 target = tp->rp->unwrapped_server;
5919 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5923 domain = mono_domain_get ();
5924 method = msg->method->method;
5925 sig = mono_method_signature (method);
5927 for (i = 0; i < sig->param_count; i++) {
5928 if (sig->params [i]->byref)
5932 if (!object_array_klass) {
5935 klass = mono_array_class_get (mono_defaults.object_class, 1);
5938 mono_memory_barrier ();
5939 object_array_klass = klass;
5942 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5943 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5946 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5948 for (i = 0, j = 0; i < sig->param_count; i++) {
5949 if (sig->params [i]->byref) {
5951 arg = mono_array_get (msg->args, gpointer, i);
5952 mono_array_setref (*out_args, j, arg);
5961 * mono_object_to_string:
5963 * @exc: Any exception thrown by ToString (). May be NULL.
5965 * Returns: the result of calling ToString () on an object.
5968 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5970 static MonoMethod *to_string = NULL;
5976 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5978 method = mono_object_get_virtual_method (obj, to_string);
5980 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5984 * mono_print_unhandled_exception:
5985 * @exc: The exception
5987 * Prints the unhandled exception.
5990 mono_print_unhandled_exception (MonoObject *exc)
5993 char *message = (char*)"";
5994 gboolean free_message = FALSE;
5997 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5998 message = g_strdup ("OutOfMemoryException");
6000 str = mono_object_to_string (exc, NULL);
6002 message = mono_string_to_utf8_checked (str, &error);
6003 if (!mono_error_ok (&error)) {
6004 mono_error_cleanup (&error);
6005 message = (char *) "";
6007 free_message = TRUE;
6013 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6014 * exc->vtable->klass->name, message);
6016 g_printerr ("\nUnhandled Exception: %s\n", message);
6023 * mono_delegate_ctor:
6024 * @this: pointer to an uninitialized delegate object
6025 * @target: target object
6026 * @addr: pointer to native code
6029 * Initialize a delegate and sets a specific method, not the one
6030 * associated with addr. This is useful when sharing generic code.
6031 * In that case addr will most probably not be associated with the
6032 * correct instantiation of the method.
6035 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6037 MonoDelegate *delegate = (MonoDelegate *)this;
6044 delegate->method = method;
6046 class = this->vtable->klass;
6047 mono_stats.delegate_creations++;
6049 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6051 method = mono_marshal_get_remoting_invoke (method);
6052 delegate->method_ptr = mono_compile_method (method);
6053 MONO_OBJECT_SETREF (delegate, target, target);
6054 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6055 method = mono_marshal_get_unbox_wrapper (method);
6056 delegate->method_ptr = mono_compile_method (method);
6057 MONO_OBJECT_SETREF (delegate, target, target);
6059 delegate->method_ptr = addr;
6060 MONO_OBJECT_SETREF (delegate, target, target);
6063 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6067 * mono_delegate_ctor:
6068 * @this: pointer to an uninitialized delegate object
6069 * @target: target object
6070 * @addr: pointer to native code
6072 * This is used to initialize a delegate.
6075 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6077 MonoDomain *domain = mono_domain_get ();
6079 MonoMethod *method = NULL;
6083 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6084 method = ji->method;
6085 g_assert (!method->klass->generic_container);
6088 mono_delegate_ctor_with_method (this, target, addr, method);
6092 * mono_method_call_message_new:
6093 * @method: method to encapsulate
6094 * @params: parameters to the method
6095 * @invoke: optional, delegate invoke.
6096 * @cb: async callback delegate.
6097 * @state: state passed to the async callback.
6099 * Translates arguments pointers into a MonoMethodMessage.
6102 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6103 MonoDelegate **cb, MonoObject **state)
6105 MonoDomain *domain = mono_domain_get ();
6106 MonoMethodSignature *sig = mono_method_signature (method);
6107 MonoMethodMessage *msg;
6110 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6113 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6114 count = sig->param_count - 2;
6116 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6117 count = sig->param_count;
6120 for (i = 0; i < count; i++) {
6125 if (sig->params [i]->byref)
6126 vpos = *((gpointer *)params [i]);
6130 type = sig->params [i]->type;
6131 class = mono_class_from_mono_type (sig->params [i]);
6133 if (class->valuetype)
6134 arg = mono_value_box (domain, class, vpos);
6136 arg = *((MonoObject **)vpos);
6138 mono_array_setref (msg->args, i, arg);
6141 if (cb != NULL && state != NULL) {
6142 *cb = *((MonoDelegate **)params [i]);
6144 *state = *((MonoObject **)params [i]);
6151 * mono_method_return_message_restore:
6153 * Restore results from message based processing back to arguments pointers
6156 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6158 MonoMethodSignature *sig = mono_method_signature (method);
6159 int i, j, type, size, out_len;
6161 if (out_args == NULL)
6163 out_len = mono_array_length (out_args);
6167 for (i = 0, j = 0; i < sig->param_count; i++) {
6168 MonoType *pt = sig->params [i];
6173 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6175 arg = mono_array_get (out_args, gpointer, j);
6178 g_assert (type != MONO_TYPE_VOID);
6180 if (MONO_TYPE_IS_REFERENCE (pt)) {
6181 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6184 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6185 size = mono_class_value_size (class, NULL);
6186 if (class->has_references)
6187 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6189 mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6191 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6192 mono_gc_bzero (*((gpointer *)params [i]), size);
6202 * mono_load_remote_field:
6203 * @this: pointer to an object
6204 * @klass: klass of the object containing @field
6205 * @field: the field to load
6206 * @res: a storage to store the result
6208 * This method is called by the runtime on attempts to load fields of
6209 * transparent proxy objects. @this points to such TP, @klass is the class of
6210 * the object containing @field. @res is a storage location which can be
6211 * used to store the result.
6213 * Returns: an address pointing to the value of field.
6216 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6218 static MonoMethod *getter = NULL;
6219 MonoDomain *domain = mono_domain_get ();
6220 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6221 MonoClass *field_class;
6222 MonoMethodMessage *msg;
6223 MonoArray *out_args;
6227 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6228 g_assert (res != NULL);
6230 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6231 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6236 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6240 field_class = mono_class_from_mono_type (field->type);
6242 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6243 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6244 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6246 full_name = mono_type_get_full_name (klass);
6247 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6248 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6251 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6253 if (exc) mono_raise_exception ((MonoException *)exc);
6255 if (mono_array_length (out_args) == 0)
6258 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6260 if (field_class->valuetype) {
6261 return ((char *)*res) + sizeof (MonoObject);
6267 * mono_load_remote_field_new:
6272 * Missing documentation.
6275 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6277 static MonoMethod *getter = NULL;
6278 MonoDomain *domain = mono_domain_get ();
6279 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6280 MonoClass *field_class;
6281 MonoMethodMessage *msg;
6282 MonoArray *out_args;
6283 MonoObject *exc, *res;
6286 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6288 field_class = mono_class_from_mono_type (field->type);
6290 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6292 if (field_class->valuetype) {
6293 res = mono_object_new (domain, field_class);
6294 val = ((gchar *) res) + sizeof (MonoObject);
6298 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6303 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6307 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6308 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6310 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6312 full_name = mono_type_get_full_name (klass);
6313 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6314 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6317 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6319 if (exc) mono_raise_exception ((MonoException *)exc);
6321 if (mono_array_length (out_args) == 0)
6324 res = mono_array_get (out_args, MonoObject *, 0);
6330 * mono_store_remote_field:
6331 * @this: pointer to an object
6332 * @klass: klass of the object containing @field
6333 * @field: the field to load
6334 * @val: the value/object to store
6336 * This method is called by the runtime on attempts to store fields of
6337 * transparent proxy objects. @this points to such TP, @klass is the class of
6338 * the object containing @field. @val is the new value to store in @field.
6341 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6343 static MonoMethod *setter = NULL;
6344 MonoDomain *domain = mono_domain_get ();
6345 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6346 MonoClass *field_class;
6347 MonoMethodMessage *msg;
6348 MonoArray *out_args;
6353 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6355 field_class = mono_class_from_mono_type (field->type);
6357 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6358 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6359 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6364 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6368 if (field_class->valuetype)
6369 arg = mono_value_box (domain, field_class, val);
6371 arg = *((MonoObject **)val);
6374 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6375 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6377 full_name = mono_type_get_full_name (klass);
6378 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6379 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6380 mono_array_setref (msg->args, 2, arg);
6383 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6385 if (exc) mono_raise_exception ((MonoException *)exc);
6389 * mono_store_remote_field_new:
6395 * Missing documentation
6398 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6400 static MonoMethod *setter = NULL;
6401 MonoDomain *domain = mono_domain_get ();
6402 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6403 MonoClass *field_class;
6404 MonoMethodMessage *msg;
6405 MonoArray *out_args;
6409 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6411 field_class = mono_class_from_mono_type (field->type);
6413 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6414 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6415 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6420 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6424 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6425 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6427 full_name = mono_type_get_full_name (klass);
6428 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6429 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6430 mono_array_setref (msg->args, 2, arg);
6433 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6435 if (exc) mono_raise_exception ((MonoException *)exc);
6439 * mono_create_ftnptr:
6441 * Given a function address, create a function descriptor for it.
6442 * This is only needed on some platforms.
6445 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6447 return callbacks.create_ftnptr (domain, addr);
6451 * mono_get_addr_from_ftnptr:
6453 * Given a pointer to a function descriptor, return the function address.
6454 * This is only needed on some platforms.
6457 mono_get_addr_from_ftnptr (gpointer descr)
6459 return callbacks.get_addr_from_ftnptr (descr);
6463 * mono_string_chars:
6466 * Returns a pointer to the UCS16 characters stored in the MonoString
6469 mono_string_chars (MonoString *s)
6475 * mono_string_length:
6478 * Returns the lenght in characters of the string
6481 mono_string_length (MonoString *s)
6487 * mono_array_length:
6488 * @array: a MonoArray*
6490 * Returns the total number of elements in the array. This works for
6491 * both vectors and multidimensional arrays.
6494 mono_array_length (MonoArray *array)
6496 return array->max_length;
6500 * mono_array_addr_with_size:
6501 * @array: a MonoArray*
6502 * @size: size of the array elements
6503 * @idx: index into the array
6505 * Returns the address of the @idx element in the array.
6508 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6510 return ((char*)(array)->vector) + size * idx;