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;
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));
1906 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1907 if (class->interface_offsets_count) {
1908 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1909 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1910 mono_stats.imt_number_of_tables++;
1911 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1914 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1915 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1918 mono_stats.used_class_count++;
1919 mono_stats.class_vtable_size += vtable_size;
1920 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1923 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1925 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1927 vt->rank = class->rank;
1928 vt->domain = domain;
1930 mono_class_compute_gc_descriptor (class);
1932 * We can't use typed allocation in the non-root domains, since the
1933 * collector needs the GC descriptor stored in the vtable even after
1934 * the mempool containing the vtable is destroyed when the domain is
1935 * unloaded. An alternative might be to allocate vtables in the GC
1936 * heap, but this does not seem to work (it leads to crashes inside
1937 * libgc). If that approach is tried, two gc descriptors need to be
1938 * allocated for each class: one for the root domain, and one for all
1939 * other domains. The second descriptor should contain a bit for the
1940 * vtable field in MonoObject, since we can no longer assume the
1941 * vtable is reachable by other roots after the appdomain is unloaded.
1943 #ifdef HAVE_BOEHM_GC
1944 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1945 vt->gc_descr = GC_NO_DESCRIPTOR;
1948 vt->gc_descr = class->gc_descr;
1950 if ((class_size = mono_class_data_size (class))) {
1951 if (class->has_static_refs) {
1952 gpointer statics_gc_descr;
1954 gsize default_bitmap [4] = {0};
1957 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1958 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1959 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1960 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1961 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1962 if (bitmap != default_bitmap)
1965 vt->data = mono_domain_alloc0 (domain, class_size);
1967 mono_stats.class_static_data_size += class_size;
1972 while ((field = mono_class_get_fields (class, &iter))) {
1973 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1975 if (mono_field_is_deleted (field))
1977 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1978 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1979 if (special_static != SPECIAL_STATIC_NONE) {
1980 guint32 size, offset;
1982 gsize default_bitmap [4] = {0};
1986 if (mono_type_is_reference (field->type)) {
1987 default_bitmap [0] = 1;
1989 bitmap = default_bitmap;
1990 } else if (mono_type_is_struct (field->type)) {
1991 fclass = mono_class_from_mono_type (field->type);
1992 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1994 default_bitmap [0] = 0;
1996 bitmap = default_bitmap;
1998 size = mono_type_size (field->type, &align);
1999 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2000 if (!domain->special_static_fields)
2001 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2002 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2003 if (bitmap != default_bitmap)
2006 * This marks the field as special static to speed up the
2007 * checks in mono_field_static_get/set_value ().
2013 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2014 MonoClass *fklass = mono_class_from_mono_type (field->type);
2015 const char *data = mono_field_get_data (field);
2017 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2018 t = (char*)vt->data + field->offset;
2019 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2022 if (fklass->valuetype) {
2023 memcpy (t, data, mono_class_value_size (fklass, NULL));
2025 /* it's a pointer type: add check */
2026 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2033 vt->max_interface_id = class->max_interface_id;
2034 vt->interface_bitmap = class->interface_bitmap;
2036 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2037 // class->name, class->interface_offsets_count);
2039 if (! ARCH_USE_IMT) {
2040 /* initialize interface offsets */
2041 for (i = 0; i < class->interface_offsets_count; ++i) {
2042 int interface_id = class->interfaces_packed [i]->interface_id;
2043 int slot = class->interface_offsets_packed [i];
2044 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2048 /* class_vtable_array keeps an array of created vtables
2050 g_ptr_array_add (domain->class_vtable_array, vt);
2051 /* class->runtime_info is protected by the loader lock, both when
2052 * it it enlarged and when it is stored info.
2055 old_info = class->runtime_info;
2056 if (old_info && old_info->max_domain >= domain->domain_id) {
2057 /* someone already created a large enough runtime info */
2058 mono_memory_barrier ();
2059 old_info->domain_vtables [domain->domain_id] = vt;
2061 int new_size = domain->domain_id;
2063 new_size = MAX (new_size, old_info->max_domain);
2065 /* make the new size a power of two */
2067 while (new_size > i)
2070 /* this is a bounded memory retention issue: may want to
2071 * handle it differently when we'll have a rcu-like system.
2073 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2074 runtime_info->max_domain = new_size - 1;
2075 /* copy the stuff from the older info */
2077 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2079 runtime_info->domain_vtables [domain->domain_id] = vt;
2081 mono_memory_barrier ();
2082 class->runtime_info = runtime_info;
2085 /* Initialize vtable */
2086 if (callbacks.get_vtable_trampoline) {
2087 // This also covers the AOT case
2088 for (i = 0; i < class->vtable_size; ++i) {
2089 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2092 mono_class_setup_vtable (class);
2094 for (i = 0; i < class->vtable_size; ++i) {
2097 if ((cm = class->vtable [i]))
2098 vt->vtable [i] = arch_create_jit_trampoline (cm);
2102 if (ARCH_USE_IMT && imt_table_bytes) {
2103 /* Now that the vtable is full, we can actually fill up the IMT */
2104 if (callbacks.get_imt_trampoline) {
2105 /* lazy construction of the IMT entries enabled */
2106 for (i = 0; i < MONO_IMT_SIZE; ++i)
2107 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2109 build_imt (class, vt, domain, interface_offsets, NULL);
2113 mono_domain_unlock (domain);
2114 mono_loader_unlock ();
2116 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2117 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2118 mono_raise_exception (mono_class_get_exception_for_failure (class));
2120 /* make sure the parent is initialized */
2121 /*FIXME shouldn't this fail the current type?*/
2123 mono_class_vtable_full (domain, class->parent, raise_on_error);
2125 /*FIXME check for OOM*/
2126 vt->type = mono_type_get_object (domain, &class->byval_arg);
2127 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2128 /* This is unregistered in
2129 unregister_vtable_reflection_type() in
2131 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2132 if (class->contextbound)
2141 * mono_class_proxy_vtable:
2142 * @domain: the application domain
2143 * @remove_class: the remote class
2145 * Creates a vtable for transparent proxies. It is basically
2146 * a copy of the real vtable of the class wrapped in @remote_class,
2147 * but all function pointers invoke the remoting functions, and
2148 * vtable->klass points to the transparent proxy class, and not to @class.
2151 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2154 MonoVTable *vt, *pvt;
2155 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2157 GSList *extra_interfaces = NULL;
2158 MonoClass *class = remote_class->proxy_class;
2159 gpointer *interface_offsets;
2163 #ifdef COMPRESSED_INTERFACE_BITMAP
2167 vt = mono_class_vtable (domain, class);
2168 g_assert (vt); /*FIXME property handle failure*/
2169 max_interface_id = vt->max_interface_id;
2171 /* Calculate vtable space for extra interfaces */
2172 for (j = 0; j < remote_class->interface_count; j++) {
2173 MonoClass* iclass = remote_class->interfaces[j];
2177 /*FIXME test for interfaces with variant generic arguments*/
2178 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2179 continue; /* interface implemented by the class */
2180 if (g_slist_find (extra_interfaces, iclass))
2183 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2185 method_count = mono_class_num_methods (iclass);
2187 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2188 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2190 for (i = 0; i < ifaces->len; ++i) {
2191 MonoClass *ic = g_ptr_array_index (ifaces, i);
2192 /*FIXME test for interfaces with variant generic arguments*/
2193 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2194 continue; /* interface implemented by the class */
2195 if (g_slist_find (extra_interfaces, ic))
2197 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2198 method_count += mono_class_num_methods (ic);
2200 g_ptr_array_free (ifaces, TRUE);
2203 extra_interface_vtsize += method_count * sizeof (gpointer);
2204 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2208 mono_stats.imt_number_of_tables++;
2209 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2210 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2211 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2213 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2214 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2217 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2219 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2221 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2223 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2224 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2226 pvt->klass = mono_defaults.transparent_proxy_class;
2227 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2228 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2230 /* initialize vtable */
2231 mono_class_setup_vtable (class);
2232 for (i = 0; i < class->vtable_size; ++i) {
2235 if ((cm = class->vtable [i]))
2236 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2238 pvt->vtable [i] = NULL;
2241 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2242 /* create trampolines for abstract methods */
2243 for (k = class; k; k = k->parent) {
2245 gpointer iter = NULL;
2246 while ((m = mono_class_get_methods (k, &iter)))
2247 if (!pvt->vtable [m->slot])
2248 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2252 pvt->max_interface_id = max_interface_id;
2253 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2254 #ifdef COMPRESSED_INTERFACE_BITMAP
2255 bitmap = g_malloc0 (bsize);
2257 bitmap = mono_domain_alloc0 (domain, bsize);
2260 if (! ARCH_USE_IMT) {
2261 /* initialize interface offsets */
2262 for (i = 0; i < class->interface_offsets_count; ++i) {
2263 int interface_id = class->interfaces_packed [i]->interface_id;
2264 int slot = class->interface_offsets_packed [i];
2265 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2268 for (i = 0; i < class->interface_offsets_count; ++i) {
2269 int interface_id = class->interfaces_packed [i]->interface_id;
2270 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2273 if (extra_interfaces) {
2274 int slot = class->vtable_size;
2280 /* Create trampolines for the methods of the interfaces */
2281 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2282 interf = list_item->data;
2284 if (! ARCH_USE_IMT) {
2285 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2287 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2291 while ((cm = mono_class_get_methods (interf, &iter)))
2292 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2294 slot += mono_class_num_methods (interf);
2296 if (! ARCH_USE_IMT) {
2297 g_slist_free (extra_interfaces);
2302 /* Now that the vtable is full, we can actually fill up the IMT */
2303 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2304 if (extra_interfaces) {
2305 g_slist_free (extra_interfaces);
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2311 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2312 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2315 pvt->interface_bitmap = bitmap;
2321 * mono_class_field_is_special_static:
2323 * Returns whether @field is a thread/context static field.
2326 mono_class_field_is_special_static (MonoClassField *field)
2328 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2330 if (mono_field_is_deleted (field))
2332 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2333 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2340 * mono_class_field_get_special_static_type:
2341 * @field: The MonoClassField describing the field.
2343 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2344 * SPECIAL_STATIC_NONE otherwise.
2347 mono_class_field_get_special_static_type (MonoClassField *field)
2349 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2350 return SPECIAL_STATIC_NONE;
2351 if (mono_field_is_deleted (field))
2352 return SPECIAL_STATIC_NONE;
2353 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2354 return field_is_special_static (field->parent, field);
2355 return SPECIAL_STATIC_NONE;
2359 * mono_class_has_special_static_fields:
2361 * Returns whenever @klass has any thread/context static fields.
2364 mono_class_has_special_static_fields (MonoClass *klass)
2366 MonoClassField *field;
2370 while ((field = mono_class_get_fields (klass, &iter))) {
2371 g_assert (field->parent == klass);
2372 if (mono_class_field_is_special_static (field))
2380 * create_remote_class_key:
2381 * Creates an array of pointers that can be used as a hash key for a remote class.
2382 * The first element of the array is the number of pointers.
2385 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2390 if (remote_class == NULL) {
2391 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2392 key = g_malloc (sizeof(gpointer) * 3);
2393 key [0] = GINT_TO_POINTER (2);
2394 key [1] = mono_defaults.marshalbyrefobject_class;
2395 key [2] = extra_class;
2397 key = g_malloc (sizeof(gpointer) * 2);
2398 key [0] = GINT_TO_POINTER (1);
2399 key [1] = extra_class;
2402 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2403 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2404 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2405 key [1] = remote_class->proxy_class;
2407 // Keep the list of interfaces sorted
2408 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2409 if (extra_class && remote_class->interfaces [i] > extra_class) {
2410 key [j++] = extra_class;
2413 key [j] = remote_class->interfaces [i];
2416 key [j] = extra_class;
2418 // Replace the old class. The interface list is the same
2419 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2420 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2421 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2422 for (i = 0; i < remote_class->interface_count; i++)
2423 key [2 + i] = remote_class->interfaces [i];
2431 * copy_remote_class_key:
2433 * Make a copy of KEY in the domain and return the copy.
2436 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2438 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2439 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2441 memcpy (mp_key, key, key_size);
2447 * mono_remote_class:
2448 * @domain: the application domain
2449 * @class_name: name of the remote class
2451 * Creates and initializes a MonoRemoteClass object for a remote type.
2453 * Can raise an exception on failure.
2456 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2459 MonoRemoteClass *rc;
2460 gpointer* key, *mp_key;
2463 key = create_remote_class_key (NULL, proxy_class);
2465 mono_domain_lock (domain);
2466 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2470 mono_domain_unlock (domain);
2474 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2475 if (!mono_error_ok (&error)) {
2477 mono_domain_unlock (domain);
2478 mono_error_raise_exception (&error);
2481 mp_key = copy_remote_class_key (domain, key);
2485 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2486 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2487 rc->interface_count = 1;
2488 rc->interfaces [0] = proxy_class;
2489 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2491 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2492 rc->interface_count = 0;
2493 rc->proxy_class = proxy_class;
2496 rc->default_vtable = NULL;
2497 rc->xdomain_vtable = NULL;
2498 rc->proxy_class_name = name;
2499 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2501 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2503 mono_domain_unlock (domain);
2508 * clone_remote_class:
2509 * Creates a copy of the remote_class, adding the provided class or interface
2511 static MonoRemoteClass*
2512 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2514 MonoRemoteClass *rc;
2515 gpointer* key, *mp_key;
2517 key = create_remote_class_key (remote_class, extra_class);
2518 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2524 mp_key = copy_remote_class_key (domain, key);
2528 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2530 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2531 rc->proxy_class = remote_class->proxy_class;
2532 rc->interface_count = remote_class->interface_count + 1;
2534 // Keep the list of interfaces sorted, since the hash key of
2535 // the remote class depends on this
2536 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2537 if (remote_class->interfaces [i] > extra_class && i == j)
2538 rc->interfaces [j++] = extra_class;
2539 rc->interfaces [j] = remote_class->interfaces [i];
2542 rc->interfaces [j] = extra_class;
2544 // Replace the old class. The interface array is the same
2545 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2546 rc->proxy_class = extra_class;
2547 rc->interface_count = remote_class->interface_count;
2548 if (rc->interface_count > 0)
2549 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2552 rc->default_vtable = NULL;
2553 rc->xdomain_vtable = NULL;
2554 rc->proxy_class_name = remote_class->proxy_class_name;
2556 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2562 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2564 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2565 mono_domain_lock (domain);
2566 if (rp->target_domain_id != -1) {
2567 if (remote_class->xdomain_vtable == NULL)
2568 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2569 mono_domain_unlock (domain);
2570 mono_loader_unlock ();
2571 return remote_class->xdomain_vtable;
2573 if (remote_class->default_vtable == NULL) {
2576 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2577 klass = mono_class_from_mono_type (type);
2578 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2579 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2581 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2584 mono_domain_unlock (domain);
2585 mono_loader_unlock ();
2586 return remote_class->default_vtable;
2590 * mono_upgrade_remote_class:
2591 * @domain: the application domain
2592 * @tproxy: the proxy whose remote class has to be upgraded.
2593 * @klass: class to which the remote class can be casted.
2595 * Updates the vtable of the remote class by adding the necessary method slots
2596 * and interface offsets so it can be safely casted to klass. klass can be a
2597 * class or an interface.
2600 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2602 MonoTransparentProxy *tproxy;
2603 MonoRemoteClass *remote_class;
2604 gboolean redo_vtable;
2606 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2607 mono_domain_lock (domain);
2609 tproxy = (MonoTransparentProxy*) proxy_object;
2610 remote_class = tproxy->remote_class;
2612 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2615 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2616 if (remote_class->interfaces [i] == klass)
2617 redo_vtable = FALSE;
2620 redo_vtable = (remote_class->proxy_class != klass);
2624 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2625 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2628 mono_domain_unlock (domain);
2629 mono_loader_unlock ();
2634 * mono_object_get_virtual_method:
2635 * @obj: object to operate on.
2638 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2639 * the instance of a callvirt of method.
2642 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2645 MonoMethod **vtable;
2647 MonoMethod *res = NULL;
2649 klass = mono_object_class (obj);
2650 if (klass == mono_defaults.transparent_proxy_class) {
2651 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2657 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2660 mono_class_setup_vtable (klass);
2661 vtable = klass->vtable;
2663 if (method->slot == -1) {
2664 /* method->slot might not be set for instances of generic methods */
2665 if (method->is_inflated) {
2666 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2667 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2670 g_assert_not_reached ();
2674 /* check method->slot is a valid index: perform isinstance? */
2675 if (method->slot != -1) {
2676 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2678 gboolean variance_used = FALSE;
2679 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2680 g_assert (iface_offset > 0);
2681 res = vtable [iface_offset + method->slot];
2684 res = vtable [method->slot];
2689 /* It may be an interface, abstract class method or generic method */
2690 if (!res || mono_method_signature (res)->generic_param_count)
2693 /* generic methods demand invoke_with_check */
2694 if (mono_method_signature (res)->generic_param_count)
2695 res = mono_marshal_get_remoting_invoke_with_check (res);
2698 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2699 res = mono_cominterop_get_invoke (res);
2702 res = mono_marshal_get_remoting_invoke (res);
2705 if (method->is_inflated) {
2706 /* Have to inflate the result */
2707 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2717 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2719 g_error ("runtime invoke called on uninitialized runtime");
2723 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2726 * mono_runtime_invoke:
2727 * @method: method to invoke
2728 * @obJ: object instance
2729 * @params: arguments to the method
2730 * @exc: exception information.
2732 * Invokes the method represented by @method on the object @obj.
2734 * obj is the 'this' pointer, it should be NULL for static
2735 * methods, a MonoObject* for object instances and a pointer to
2736 * the value type for value types.
2738 * The params array contains the arguments to the method with the
2739 * same convention: MonoObject* pointers for object instances and
2740 * pointers to the value type otherwise.
2742 * From unmanaged code you'll usually use the
2743 * mono_runtime_invoke() variant.
2745 * Note that this function doesn't handle virtual methods for
2746 * you, it will exec the exact method you pass: we still need to
2747 * expose a function to lookup the derived class implementation
2748 * of a virtual method (there are examples of this in the code,
2751 * You can pass NULL as the exc argument if you don't want to
2752 * catch exceptions, otherwise, *exc will be set to the exception
2753 * thrown, if any. if an exception is thrown, you can't use the
2754 * MonoObject* result from the function.
2756 * If the method returns a value type, it is boxed in an object
2760 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2764 if (mono_runtime_get_no_exec ())
2765 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2767 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2768 mono_profiler_method_start_invoke (method);
2770 result = default_mono_runtime_invoke (method, obj, params, exc);
2772 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2773 mono_profiler_method_end_invoke (method);
2779 * mono_method_get_unmanaged_thunk:
2780 * @method: method to generate a thunk for.
2782 * Returns an unmanaged->managed thunk that can be used to call
2783 * a managed method directly from C.
2785 * The thunk's C signature closely matches the managed signature:
2787 * C#: public bool Equals (object obj);
2788 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2789 * MonoObject*, MonoException**);
2791 * The 1st ("this") parameter must not be used with static methods:
2793 * C#: public static bool ReferenceEquals (object a, object b);
2794 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2797 * The last argument must be a non-null pointer of a MonoException* pointer.
2798 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2799 * exception has been thrown in managed code. Otherwise it will point
2800 * to the MonoException* caught by the thunk. In this case, the result of
2801 * the thunk is undefined:
2803 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2804 * MonoException *ex = NULL;
2805 * Equals func = mono_method_get_unmanaged_thunk (method);
2806 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2808 * // handle exception
2811 * The calling convention of the thunk matches the platform's default
2812 * convention. This means that under Windows, C declarations must
2813 * contain the __stdcall attribute:
2815 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2816 * MonoObject*, MonoException**);
2820 * Value type arguments and return values are treated as they were objects:
2822 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2823 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2825 * Arguments must be properly boxed upon trunk's invocation, while return
2826 * values must be unboxed.
2829 mono_method_get_unmanaged_thunk (MonoMethod *method)
2831 method = mono_marshal_get_thunk_invoke_wrapper (method);
2832 return mono_compile_method (method);
2836 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2840 /* object fields cannot be byref, so we don't need a
2842 gpointer *p = (gpointer*)dest;
2849 case MONO_TYPE_BOOLEAN:
2851 case MONO_TYPE_U1: {
2852 guint8 *p = (guint8*)dest;
2853 *p = value ? *(guint8*)value : 0;
2858 case MONO_TYPE_CHAR: {
2859 guint16 *p = (guint16*)dest;
2860 *p = value ? *(guint16*)value : 0;
2863 #if SIZEOF_VOID_P == 4
2868 case MONO_TYPE_U4: {
2869 gint32 *p = (gint32*)dest;
2870 *p = value ? *(gint32*)value : 0;
2873 #if SIZEOF_VOID_P == 8
2878 case MONO_TYPE_U8: {
2879 gint64 *p = (gint64*)dest;
2880 *p = value ? *(gint64*)value : 0;
2883 case MONO_TYPE_R4: {
2884 float *p = (float*)dest;
2885 *p = value ? *(float*)value : 0;
2888 case MONO_TYPE_R8: {
2889 double *p = (double*)dest;
2890 *p = value ? *(double*)value : 0;
2893 case MONO_TYPE_STRING:
2894 case MONO_TYPE_SZARRAY:
2895 case MONO_TYPE_CLASS:
2896 case MONO_TYPE_OBJECT:
2897 case MONO_TYPE_ARRAY:
2898 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2900 case MONO_TYPE_FNPTR:
2901 case MONO_TYPE_PTR: {
2902 gpointer *p = (gpointer*)dest;
2903 *p = deref_pointer? *(gpointer*)value: value;
2906 case MONO_TYPE_VALUETYPE:
2907 /* note that 't' and 'type->type' can be different */
2908 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2909 t = mono_class_enum_basetype (type->data.klass)->type;
2912 MonoClass *class = mono_class_from_mono_type (type);
2913 int size = mono_class_value_size (class, NULL);
2915 memset (dest, 0, size);
2917 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2920 case MONO_TYPE_GENERICINST:
2921 t = type->data.generic_class->container_class->byval_arg.type;
2924 g_warning ("got type %x", type->type);
2925 g_assert_not_reached ();
2930 * mono_field_set_value:
2931 * @obj: Instance object
2932 * @field: MonoClassField describing the field to set
2933 * @value: The value to be set
2935 * Sets the value of the field described by @field in the object instance @obj
2936 * to the value passed in @value. This method should only be used for instance
2937 * fields. For static fields, use mono_field_static_set_value.
2939 * The value must be on the native format of the field type.
2942 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2946 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2948 dest = (char*)obj + field->offset;
2949 set_value (field->type, dest, value, FALSE);
2953 * mono_field_static_set_value:
2954 * @field: MonoClassField describing the field to set
2955 * @value: The value to be set
2957 * Sets the value of the static field described by @field
2958 * to the value passed in @value.
2960 * The value must be on the native format of the field type.
2963 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2967 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2968 /* you cant set a constant! */
2969 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2971 if (field->offset == -1) {
2972 /* Special static */
2975 mono_domain_lock (vt->domain);
2976 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2977 mono_domain_unlock (vt->domain);
2978 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2980 dest = (char*)vt->data + field->offset;
2982 set_value (field->type, dest, value, FALSE);
2985 /* Used by the debugger */
2987 mono_vtable_get_static_field_data (MonoVTable *vt)
2993 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2997 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2998 if (field->offset == -1) {
2999 /* Special static */
3002 mono_domain_lock (vt->domain);
3003 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3004 mono_domain_unlock (vt->domain);
3005 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3007 src = (guint8*)vt->data + field->offset;
3010 src = (guint8*)obj + field->offset;
3017 * mono_field_get_value:
3018 * @obj: Object instance
3019 * @field: MonoClassField describing the field to fetch information from
3020 * @value: pointer to the location where the value will be stored
3022 * Use this routine to get the value of the field @field in the object
3025 * The pointer provided by value must be of the field type, for reference
3026 * types this is a MonoObject*, for value types its the actual pointer to
3031 * mono_field_get_value (obj, int_field, &i);
3034 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3040 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3042 src = (char*)obj + field->offset;
3043 set_value (field->type, value, src, TRUE);
3047 * mono_field_get_value_object:
3048 * @domain: domain where the object will be created (if boxing)
3049 * @field: MonoClassField describing the field to fetch information from
3050 * @obj: The object instance for the field.
3052 * Returns: a new MonoObject with the value from the given field. If the
3053 * field represents a value type, the value is boxed.
3057 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3061 MonoVTable *vtable = NULL;
3063 gboolean is_static = FALSE;
3064 gboolean is_ref = FALSE;
3065 gboolean is_literal = FALSE;
3066 gboolean is_ptr = FALSE;
3068 MonoType *type = mono_field_get_type_checked (field, &error);
3070 if (!mono_error_ok (&error))
3071 mono_error_raise_exception (&error);
3073 switch (type->type) {
3074 case MONO_TYPE_STRING:
3075 case MONO_TYPE_OBJECT:
3076 case MONO_TYPE_CLASS:
3077 case MONO_TYPE_ARRAY:
3078 case MONO_TYPE_SZARRAY:
3083 case MONO_TYPE_BOOLEAN:
3086 case MONO_TYPE_CHAR:
3095 case MONO_TYPE_VALUETYPE:
3096 is_ref = type->byref;
3098 case MONO_TYPE_GENERICINST:
3099 is_ref = !mono_type_generic_inst_is_valuetype (type);
3105 g_error ("type 0x%x not handled in "
3106 "mono_field_get_value_object", type->type);
3110 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3113 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3117 vtable = mono_class_vtable (domain, field->parent);
3119 char *name = mono_type_get_full_name (field->parent);
3120 /*FIXME extend this to use the MonoError api*/
3121 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3125 if (!vtable->initialized)
3126 mono_runtime_class_init (vtable);
3134 get_default_field_value (domain, field, &o);
3135 } else if (is_static) {
3136 mono_field_static_get_value (vtable, field, &o);
3138 mono_field_get_value (obj, field, &o);
3144 static MonoMethod *m;
3150 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3151 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3157 get_default_field_value (domain, field, v);
3158 } else if (is_static) {
3159 mono_field_static_get_value (vtable, field, v);
3161 mono_field_get_value (obj, field, v);
3164 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3166 args [1] = mono_type_get_object (mono_domain_get (), type);
3168 return mono_runtime_invoke (m, NULL, args, NULL);
3171 /* boxed value type */
3172 klass = mono_class_from_mono_type (type);
3174 if (mono_class_is_nullable (klass))
3175 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3177 o = mono_object_new (domain, klass);
3178 v = ((gchar *) o) + sizeof (MonoObject);
3181 get_default_field_value (domain, field, v);
3182 } else if (is_static) {
3183 mono_field_static_get_value (vtable, field, v);
3185 mono_field_get_value (obj, field, v);
3192 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3195 const char *p = blob;
3196 mono_metadata_decode_blob_size (p, &p);
3199 case MONO_TYPE_BOOLEAN:
3202 *(guint8 *) value = *p;
3204 case MONO_TYPE_CHAR:
3207 *(guint16*) value = read16 (p);
3211 *(guint32*) value = read32 (p);
3215 *(guint64*) value = read64 (p);
3218 readr4 (p, (float*) value);
3221 readr8 (p, (double*) value);
3223 case MONO_TYPE_STRING:
3224 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3226 case MONO_TYPE_CLASS:
3227 *(gpointer*) value = NULL;
3231 g_warning ("type 0x%02x should not be in constant table", type);
3237 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3239 MonoTypeEnum def_type;
3242 data = mono_class_get_field_default_value (field, &def_type);
3243 mono_get_constant_value_from_blob (domain, def_type, data, value);
3247 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3251 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3253 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3254 get_default_field_value (vt->domain, field, value);
3258 if (field->offset == -1) {
3259 /* Special static */
3260 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3261 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3263 src = (char*)vt->data + field->offset;
3265 set_value (field->type, value, src, TRUE);
3269 * mono_field_static_get_value:
3270 * @vt: vtable to the object
3271 * @field: MonoClassField describing the field to fetch information from
3272 * @value: where the value is returned
3274 * Use this routine to get the value of the static field @field value.
3276 * The pointer provided by value must be of the field type, for reference
3277 * types this is a MonoObject*, for value types its the actual pointer to
3282 * mono_field_static_get_value (vt, int_field, &i);
3285 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3287 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3291 * mono_property_set_value:
3292 * @prop: MonoProperty to set
3293 * @obj: instance object on which to act
3294 * @params: parameters to pass to the propery
3295 * @exc: optional exception
3297 * Invokes the property's set method with the given arguments on the
3298 * object instance obj (or NULL for static properties).
3300 * You can pass NULL as the exc argument if you don't want to
3301 * catch exceptions, otherwise, *exc will be set to the exception
3302 * thrown, if any. if an exception is thrown, you can't use the
3303 * MonoObject* result from the function.
3306 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3308 default_mono_runtime_invoke (prop->set, obj, params, exc);
3312 * mono_property_get_value:
3313 * @prop: MonoProperty to fetch
3314 * @obj: instance object on which to act
3315 * @params: parameters to pass to the propery
3316 * @exc: optional exception
3318 * Invokes the property's get method with the given arguments on the
3319 * object instance obj (or NULL for static properties).
3321 * You can pass NULL as the exc argument if you don't want to
3322 * catch exceptions, otherwise, *exc will be set to the exception
3323 * thrown, if any. if an exception is thrown, you can't use the
3324 * MonoObject* result from the function.
3326 * Returns: the value from invoking the get method on the property.
3329 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3331 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3335 * mono_nullable_init:
3336 * @buf: The nullable structure to initialize.
3337 * @value: the value to initialize from
3338 * @klass: the type for the object
3340 * Initialize the nullable structure pointed to by @buf from @value which
3341 * should be a boxed value type. The size of @buf should be able to hold
3342 * as much data as the @klass->instance_size (which is the number of bytes
3343 * that will be copies).
3345 * Since Nullables have variable structure, we can not define a C
3346 * structure for them.
3349 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3351 MonoClass *param_class = klass->cast_class;
3353 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3354 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3356 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3358 if (param_class->has_references)
3359 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3361 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3363 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3368 * mono_nullable_box:
3369 * @buf: The buffer representing the data to be boxed
3370 * @klass: the type to box it as.
3372 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3376 mono_nullable_box (guint8 *buf, MonoClass *klass)
3378 MonoClass *param_class = klass->cast_class;
3380 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3381 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3383 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3384 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3385 if (param_class->has_references)
3386 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3388 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3396 * mono_get_delegate_invoke:
3397 * @klass: The delegate class
3399 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3402 mono_get_delegate_invoke (MonoClass *klass)
3406 /* This is called at runtime, so avoid the slower search in metadata */
3407 mono_class_setup_methods (klass);
3408 if (klass->exception_type)
3410 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3415 * mono_runtime_delegate_invoke:
3416 * @delegate: pointer to a delegate object.
3417 * @params: parameters for the delegate.
3418 * @exc: Pointer to the exception result.
3420 * Invokes the delegate method @delegate with the parameters provided.
3422 * You can pass NULL as the exc argument if you don't want to
3423 * catch exceptions, otherwise, *exc will be set to the exception
3424 * thrown, if any. if an exception is thrown, you can't use the
3425 * MonoObject* result from the function.
3428 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3432 im = mono_get_delegate_invoke (delegate->vtable->klass);
3435 return mono_runtime_invoke (im, delegate, params, exc);
3438 static char **main_args = NULL;
3439 static int num_main_args;
3442 * mono_runtime_get_main_args:
3444 * Returns: a MonoArray with the arguments passed to the main program
3447 mono_runtime_get_main_args (void)
3451 MonoDomain *domain = mono_domain_get ();
3456 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3458 for (i = 0; i < num_main_args; ++i)
3459 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3465 free_main_args (void)
3469 for (i = 0; i < num_main_args; ++i)
3470 g_free (main_args [i]);
3475 * mono_runtime_run_main:
3476 * @method: the method to start the application with (usually Main)
3477 * @argc: number of arguments from the command line
3478 * @argv: array of strings from the command line
3479 * @exc: excetption results
3481 * Execute a standard Main() method (argc/argv contains the
3482 * executable name). This method also sets the command line argument value
3483 * needed by System.Environment.
3488 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3492 MonoArray *args = NULL;
3493 MonoDomain *domain = mono_domain_get ();
3494 gchar *utf8_fullpath;
3495 MonoMethodSignature *sig;
3497 g_assert (method != NULL);
3499 mono_thread_set_main (mono_thread_current ());
3501 main_args = g_new0 (char*, argc);
3502 num_main_args = argc;
3504 if (!g_path_is_absolute (argv [0])) {
3505 gchar *basename = g_path_get_basename (argv [0]);
3506 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3510 utf8_fullpath = mono_utf8_from_external (fullpath);
3511 if(utf8_fullpath == NULL) {
3512 /* Printing the arg text will cause glib to
3513 * whinge about "Invalid UTF-8", but at least
3514 * its relevant, and shows the problem text
3517 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3518 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3525 utf8_fullpath = mono_utf8_from_external (argv[0]);
3526 if(utf8_fullpath == NULL) {
3527 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3528 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3533 main_args [0] = utf8_fullpath;
3535 for (i = 1; i < argc; ++i) {
3538 utf8_arg=mono_utf8_from_external (argv[i]);
3539 if(utf8_arg==NULL) {
3540 /* Ditto the comment about Invalid UTF-8 here */
3541 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3542 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3546 main_args [i] = utf8_arg;
3551 sig = mono_method_signature (method);
3553 g_print ("Unable to load Main method.\n");
3557 if (sig->param_count) {
3558 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3559 for (i = 0; i < argc; ++i) {
3560 /* The encodings should all work, given that
3561 * we've checked all these args for the
3564 gchar *str = mono_utf8_from_external (argv [i]);
3565 MonoString *arg = mono_string_new (domain, str);
3566 mono_array_setref (args, i, arg);
3570 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3573 mono_assembly_set_main (method->klass->image->assembly);
3575 return mono_runtime_exec_main (method, args, exc);
3579 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3581 static MonoMethod *serialize_method;
3586 if (!serialize_method) {
3587 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3588 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3591 if (!serialize_method) {
3596 g_assert (!mono_object_class (obj)->marshalbyref);
3600 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3608 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3610 static MonoMethod *deserialize_method;
3615 if (!deserialize_method) {
3616 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3617 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3619 if (!deserialize_method) {
3626 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3634 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3636 static MonoMethod *get_proxy_method;
3638 MonoDomain *domain = mono_domain_get ();
3639 MonoRealProxy *real_proxy;
3640 MonoReflectionType *reflection_type;
3641 MonoTransparentProxy *transparent_proxy;
3643 if (!get_proxy_method)
3644 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3646 g_assert (obj->vtable->klass->marshalbyref);
3648 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3649 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3651 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3652 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3655 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3659 return (MonoObject*) transparent_proxy;
3663 * mono_object_xdomain_representation
3665 * @target_domain: a domain
3666 * @exc: pointer to a MonoObject*
3668 * Creates a representation of obj in the domain target_domain. This
3669 * is either a copy of obj arrived through via serialization and
3670 * deserialization or a proxy, depending on whether the object is
3671 * serializable or marshal by ref. obj must not be in target_domain.
3673 * If the object cannot be represented in target_domain, NULL is
3674 * returned and *exc is set to an appropriate exception.
3677 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3679 MonoObject *deserialized = NULL;
3680 gboolean failure = FALSE;
3684 if (mono_object_class (obj)->marshalbyref) {
3685 deserialized = make_transparent_proxy (obj, &failure, exc);
3687 MonoDomain *domain = mono_domain_get ();
3688 MonoObject *serialized;
3690 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3691 serialized = serialize_object (obj, &failure, exc);
3692 mono_domain_set_internal_with_options (target_domain, FALSE);
3694 deserialized = deserialize_object (serialized, &failure, exc);
3695 if (domain != target_domain)
3696 mono_domain_set_internal_with_options (domain, FALSE);
3699 return deserialized;
3702 /* Used in call_unhandled_exception_delegate */
3704 create_unhandled_exception_eventargs (MonoObject *exc)
3708 MonoMethod *method = NULL;
3709 MonoBoolean is_terminating = TRUE;
3712 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3715 mono_class_init (klass);
3717 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3718 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3722 args [1] = &is_terminating;
3724 obj = mono_object_new (mono_domain_get (), klass);
3725 mono_runtime_invoke (method, obj, args, NULL);
3730 /* Used in mono_unhandled_exception */
3732 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3733 MonoObject *e = NULL;
3735 MonoDomain *current_domain = mono_domain_get ();
3737 if (domain != current_domain)
3738 mono_domain_set_internal_with_options (domain, FALSE);
3740 g_assert (domain == mono_object_domain (domain->domain));
3742 if (mono_object_domain (exc) != domain) {
3743 MonoObject *serialization_exc;
3745 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3747 if (serialization_exc) {
3749 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3752 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3753 "System.Runtime.Serialization", "SerializationException",
3754 "Could not serialize unhandled exception.");
3758 g_assert (mono_object_domain (exc) == domain);
3760 pa [0] = domain->domain;
3761 pa [1] = create_unhandled_exception_eventargs (exc);
3762 mono_runtime_delegate_invoke (delegate, pa, &e);
3764 if (domain != current_domain)
3765 mono_domain_set_internal_with_options (current_domain, FALSE);
3769 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3770 if (!mono_error_ok (&error)) {
3771 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3772 mono_error_cleanup (&error);
3774 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3780 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3783 * mono_runtime_unhandled_exception_policy_set:
3784 * @policy: the new policy
3786 * This is a VM internal routine.
3788 * Sets the runtime policy for handling unhandled exceptions.
3791 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3792 runtime_unhandled_exception_policy = policy;
3796 * mono_runtime_unhandled_exception_policy_get:
3798 * This is a VM internal routine.
3800 * Gets the runtime policy for handling unhandled exceptions.
3802 MonoRuntimeUnhandledExceptionPolicy
3803 mono_runtime_unhandled_exception_policy_get (void) {
3804 return runtime_unhandled_exception_policy;
3808 * mono_unhandled_exception:
3809 * @exc: exception thrown
3811 * This is a VM internal routine.
3813 * We call this function when we detect an unhandled exception
3814 * in the default domain.
3816 * It invokes the * UnhandledException event in AppDomain or prints
3817 * a warning to the console
3820 mono_unhandled_exception (MonoObject *exc)
3822 MonoDomain *current_domain = mono_domain_get ();
3823 MonoDomain *root_domain = mono_get_root_domain ();
3824 MonoClassField *field;
3825 MonoObject *current_appdomain_delegate;
3826 MonoObject *root_appdomain_delegate;
3828 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3829 "UnhandledException");
3832 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3833 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3834 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3835 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3836 if (current_domain != root_domain) {
3837 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3839 current_appdomain_delegate = NULL;
3842 /* set exitcode only if we will abort the process */
3844 mono_environment_exitcode_set (1);
3845 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3846 mono_print_unhandled_exception (exc);
3848 if (root_appdomain_delegate) {
3849 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3851 if (current_appdomain_delegate) {
3852 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3859 * mono_runtime_exec_managed_code:
3860 * @domain: Application domain
3861 * @main_func: function to invoke from the execution thread
3862 * @main_args: parameter to the main_func
3864 * Launch a new thread to execute a function
3866 * main_func is called back from the thread with main_args as the
3867 * parameter. The callback function is expected to start Main()
3868 * eventually. This function then waits for all managed threads to
3870 * It is not necesseray anymore to execute managed code in a subthread,
3871 * so this function should not be used anymore by default: just
3872 * execute the code and then call mono_thread_manage ().
3875 mono_runtime_exec_managed_code (MonoDomain *domain,
3876 MonoMainThreadFunc main_func,
3879 mono_thread_create (domain, main_func, main_args);
3881 mono_thread_manage ();
3885 * Execute a standard Main() method (args doesn't contain the
3889 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3894 MonoCustomAttrInfo* cinfo;
3895 gboolean has_stathread_attribute;
3896 MonoInternalThread* thread = mono_thread_internal_current ();
3902 domain = mono_object_domain (args);
3903 if (!domain->entry_assembly) {
3905 MonoAssembly *assembly;
3907 assembly = method->klass->image->assembly;
3908 domain->entry_assembly = assembly;
3909 /* Domains created from another domain already have application_base and configuration_file set */
3910 if (domain->setup->application_base == NULL) {
3911 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3914 if (domain->setup->configuration_file == NULL) {
3915 str = g_strconcat (assembly->image->name, ".config", NULL);
3916 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3918 mono_set_private_bin_path_from_config (domain);
3922 cinfo = mono_custom_attrs_from_method (method);
3924 static MonoClass *stathread_attribute = NULL;
3925 if (!stathread_attribute)
3926 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3927 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3929 mono_custom_attrs_free (cinfo);
3931 has_stathread_attribute = FALSE;
3933 if (has_stathread_attribute) {
3934 thread->apartment_state = ThreadApartmentState_STA;
3936 thread->apartment_state = ThreadApartmentState_MTA;
3938 mono_thread_init_apartment_state ();
3940 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3942 /* FIXME: check signature of method */
3943 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3945 res = mono_runtime_invoke (method, NULL, pa, exc);
3947 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3951 mono_environment_exitcode_set (rval);
3953 mono_runtime_invoke (method, NULL, pa, exc);
3957 /* If the return type of Main is void, only
3958 * set the exitcode if an exception was thrown
3959 * (we don't want to blow away an
3960 * explicitly-set exit code)
3963 mono_environment_exitcode_set (rval);
3967 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3973 * mono_install_runtime_invoke:
3974 * @func: Function to install
3976 * This is a VM internal routine
3979 mono_install_runtime_invoke (MonoInvokeFunc func)
3981 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3986 * mono_runtime_invoke_array:
3987 * @method: method to invoke
3988 * @obJ: object instance
3989 * @params: arguments to the method
3990 * @exc: exception information.
3992 * Invokes the method represented by @method on the object @obj.
3994 * obj is the 'this' pointer, it should be NULL for static
3995 * methods, a MonoObject* for object instances and a pointer to
3996 * the value type for value types.
3998 * The params array contains the arguments to the method with the
3999 * same convention: MonoObject* pointers for object instances and
4000 * pointers to the value type otherwise. The _invoke_array
4001 * variant takes a C# object[] as the params argument (MonoArray
4002 * *params): in this case the value types are boxed inside the
4003 * respective reference representation.
4005 * From unmanaged code you'll usually use the
4006 * mono_runtime_invoke() variant.
4008 * Note that this function doesn't handle virtual methods for
4009 * you, it will exec the exact method you pass: we still need to
4010 * expose a function to lookup the derived class implementation
4011 * of a virtual method (there are examples of this in the code,
4014 * You can pass NULL as the exc argument if you don't want to
4015 * catch exceptions, otherwise, *exc will be set to the exception
4016 * thrown, if any. if an exception is thrown, you can't use the
4017 * MonoObject* result from the function.
4019 * If the method returns a value type, it is boxed in an object
4023 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4026 MonoMethodSignature *sig = mono_method_signature (method);
4027 gpointer *pa = NULL;
4030 gboolean has_byref_nullables = FALSE;
4032 if (NULL != params) {
4033 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4034 for (i = 0; i < mono_array_length (params); i++) {
4035 MonoType *t = sig->params [i];
4041 case MONO_TYPE_BOOLEAN:
4044 case MONO_TYPE_CHAR:
4053 case MONO_TYPE_VALUETYPE:
4054 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4055 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4056 pa [i] = mono_array_get (params, MonoObject*, i);
4058 has_byref_nullables = TRUE;
4060 /* MS seems to create the objects if a null is passed in */
4061 if (!mono_array_get (params, MonoObject*, i))
4062 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4066 * We can't pass the unboxed vtype byref to the callee, since
4067 * that would mean the callee would be able to modify boxed
4068 * primitive types. So we (and MS) make a copy of the boxed
4069 * object, pass that to the callee, and replace the original
4070 * boxed object in the arg array with the copy.
4072 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4073 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4074 mono_array_setref (params, i, copy);
4077 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4080 case MONO_TYPE_STRING:
4081 case MONO_TYPE_OBJECT:
4082 case MONO_TYPE_CLASS:
4083 case MONO_TYPE_ARRAY:
4084 case MONO_TYPE_SZARRAY:
4086 pa [i] = mono_array_addr (params, MonoObject*, i);
4087 // FIXME: I need to check this code path
4089 pa [i] = mono_array_get (params, MonoObject*, i);
4091 case MONO_TYPE_GENERICINST:
4093 t = &t->data.generic_class->container_class->this_arg;
4095 t = &t->data.generic_class->container_class->byval_arg;
4097 case MONO_TYPE_PTR: {
4100 /* The argument should be an IntPtr */
4101 arg = mono_array_get (params, MonoObject*, i);
4105 g_assert (arg->vtable->klass == mono_defaults.int_class);
4106 pa [i] = ((MonoIntPtr*)arg)->m_value;
4111 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4116 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4119 if (mono_class_is_nullable (method->klass)) {
4120 /* Need to create a boxed vtype instead */
4126 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4130 obj = mono_object_new (mono_domain_get (), method->klass);
4131 g_assert (obj); /*maybe we should raise a TLE instead?*/
4132 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4133 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4135 if (method->klass->valuetype)
4136 o = mono_object_unbox (obj);
4139 } else if (method->klass->valuetype) {
4140 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4143 mono_runtime_invoke (method, o, pa, exc);
4146 if (mono_class_is_nullable (method->klass)) {
4147 MonoObject *nullable;
4149 /* Convert the unboxed vtype into a Nullable structure */
4150 nullable = mono_object_new (mono_domain_get (), method->klass);
4152 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4153 obj = mono_object_unbox (nullable);
4156 /* obj must be already unboxed if needed */
4157 res = mono_runtime_invoke (method, obj, pa, exc);
4159 if (sig->ret->type == MONO_TYPE_PTR) {
4160 MonoClass *pointer_class;
4161 static MonoMethod *box_method;
4163 MonoObject *box_exc;
4166 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4167 * convert it to a Pointer object.
4169 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4171 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4173 g_assert (res->vtable->klass == mono_defaults.int_class);
4174 box_args [0] = ((MonoIntPtr*)res)->m_value;
4175 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4176 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4177 g_assert (!box_exc);
4180 if (has_byref_nullables) {
4182 * The runtime invoke wrapper already converted byref nullables back,
4183 * and stored them in pa, we just need to copy them back to the
4186 for (i = 0; i < mono_array_length (params); i++) {
4187 MonoType *t = sig->params [i];
4189 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4190 mono_array_setref (params, i, pa [i]);
4199 arith_overflow (void)
4201 mono_raise_exception (mono_get_exception_overflow ());
4205 * mono_object_allocate:
4206 * @size: number of bytes to allocate
4208 * This is a very simplistic routine until we have our GC-aware
4211 * Returns: an allocated object of size @size, or NULL on failure.
4213 static inline void *
4214 mono_object_allocate (size_t size, MonoVTable *vtable)
4217 mono_stats.new_object_count++;
4218 ALLOC_OBJECT (o, vtable, size);
4224 * mono_object_allocate_ptrfree:
4225 * @size: number of bytes to allocate
4227 * Note that the memory allocated is not zeroed.
4228 * Returns: an allocated object of size @size, or NULL on failure.
4230 static inline void *
4231 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4234 mono_stats.new_object_count++;
4235 ALLOC_PTRFREE (o, vtable, size);
4239 static inline void *
4240 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4243 ALLOC_TYPED (o, size, vtable);
4244 mono_stats.new_object_count++;
4251 * @klass: the class of the object that we want to create
4253 * Returns: a newly created object whose definition is
4254 * looked up using @klass. This will not invoke any constructors,
4255 * so the consumer of this routine has to invoke any constructors on
4256 * its own to initialize the object.
4258 * It returns NULL on failure.
4261 mono_object_new (MonoDomain *domain, MonoClass *klass)
4265 MONO_ARCH_SAVE_REGS;
4266 vtable = mono_class_vtable (domain, klass);
4269 return mono_object_new_specific (vtable);
4273 * mono_object_new_pinned:
4275 * Same as mono_object_new, but the returned object will be pinned.
4276 * For SGEN, these objects will only be freed at appdomain unload.
4279 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4283 MONO_ARCH_SAVE_REGS;
4284 vtable = mono_class_vtable (domain, klass);
4289 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4291 return mono_object_new_specific (vtable);
4296 * mono_object_new_specific:
4297 * @vtable: the vtable of the object that we want to create
4299 * Returns: A newly created object with class and domain specified
4303 mono_object_new_specific (MonoVTable *vtable)
4307 MONO_ARCH_SAVE_REGS;
4309 /* check for is_com_object for COM Interop */
4310 if (vtable->remote || vtable->klass->is_com_object)
4313 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4316 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4319 mono_class_init (klass);
4321 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4323 vtable->domain->create_proxy_for_type_method = im;
4326 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4328 o = mono_runtime_invoke (im, NULL, pa, NULL);
4329 if (o != NULL) return o;
4332 return mono_object_new_alloc_specific (vtable);
4336 mono_object_new_alloc_specific (MonoVTable *vtable)
4340 if (!vtable->klass->has_references) {
4341 o = mono_object_new_ptrfree (vtable);
4342 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4343 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4345 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4346 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4348 if (G_UNLIKELY (vtable->klass->has_finalize))
4349 mono_object_register_finalizer (o);
4351 if (G_UNLIKELY (profile_allocs))
4352 mono_profiler_allocation (o, vtable->klass);
4357 mono_object_new_fast (MonoVTable *vtable)
4360 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4365 mono_object_new_ptrfree (MonoVTable *vtable)
4368 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4369 #if NEED_TO_ZERO_PTRFREE
4370 /* an inline memset is much faster for the common vcase of small objects
4371 * note we assume the allocated size is a multiple of sizeof (void*).
4373 if (vtable->klass->instance_size < 128) {
4375 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4376 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4382 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4389 mono_object_new_ptrfree_box (MonoVTable *vtable)
4392 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4393 /* the object will be boxed right away, no need to memzero it */
4398 * mono_class_get_allocation_ftn:
4400 * @for_box: the object will be used for boxing
4401 * @pass_size_in_words:
4403 * Return the allocation function appropriate for the given class.
4407 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4409 *pass_size_in_words = FALSE;
4411 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4412 profile_allocs = FALSE;
4414 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4415 return mono_object_new_specific;
4417 if (!vtable->klass->has_references) {
4418 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4420 return mono_object_new_ptrfree_box;
4421 return mono_object_new_ptrfree;
4424 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4426 return mono_object_new_fast;
4429 * FIXME: This is actually slower than mono_object_new_fast, because
4430 * of the overhead of parameter passing.
4433 *pass_size_in_words = TRUE;
4434 #ifdef GC_REDIRECT_TO_LOCAL
4435 return GC_local_gcj_fast_malloc;
4437 return GC_gcj_fast_malloc;
4442 return mono_object_new_specific;
4446 * mono_object_new_from_token:
4447 * @image: Context where the type_token is hosted
4448 * @token: a token of the type that we want to create
4450 * Returns: A newly created object whose definition is
4451 * looked up using @token in the @image image
4454 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4458 class = mono_class_get (image, token);
4460 return mono_object_new (domain, class);
4465 * mono_object_clone:
4466 * @obj: the object to clone
4468 * Returns: A newly created object who is a shallow copy of @obj
4471 mono_object_clone (MonoObject *obj)
4474 int size = obj->vtable->klass->instance_size;
4476 if (obj->vtable->klass->rank)
4477 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4479 o = mono_object_allocate (size, obj->vtable);
4481 if (obj->vtable->klass->has_references) {
4482 mono_gc_wbarrier_object_copy (o, obj);
4484 int size = obj->vtable->klass->instance_size;
4485 /* do not copy the sync state */
4486 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4488 if (G_UNLIKELY (profile_allocs))
4489 mono_profiler_allocation (o, obj->vtable->klass);
4491 if (obj->vtable->klass->has_finalize)
4492 mono_object_register_finalizer (o);
4497 * mono_array_full_copy:
4498 * @src: source array to copy
4499 * @dest: destination array
4501 * Copies the content of one array to another with exactly the same type and size.
4504 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4507 MonoClass *klass = src->obj.vtable->klass;
4509 MONO_ARCH_SAVE_REGS;
4511 g_assert (klass == dest->obj.vtable->klass);
4513 size = mono_array_length (src);
4514 g_assert (size == mono_array_length (dest));
4515 size *= mono_array_element_size (klass);
4517 if (klass->element_class->valuetype) {
4518 if (klass->element_class->has_references)
4519 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4521 memcpy (&dest->vector, &src->vector, size);
4523 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4526 memcpy (&dest->vector, &src->vector, size);
4531 * mono_array_clone_in_domain:
4532 * @domain: the domain in which the array will be cloned into
4533 * @array: the array to clone
4535 * This routine returns a copy of the array that is hosted on the
4536 * specified MonoDomain.
4539 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4544 MonoClass *klass = array->obj.vtable->klass;
4546 MONO_ARCH_SAVE_REGS;
4548 if (array->bounds == NULL) {
4549 size = mono_array_length (array);
4550 o = mono_array_new_full (domain, klass, &size, NULL);
4552 size *= mono_array_element_size (klass);
4554 if (klass->element_class->valuetype) {
4555 if (klass->element_class->has_references)
4556 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4558 memcpy (&o->vector, &array->vector, size);
4560 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4563 memcpy (&o->vector, &array->vector, size);
4568 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4569 size = mono_array_element_size (klass);
4570 for (i = 0; i < klass->rank; ++i) {
4571 sizes [i] = array->bounds [i].length;
4572 size *= array->bounds [i].length;
4573 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4575 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4577 if (klass->element_class->valuetype) {
4578 if (klass->element_class->has_references)
4579 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4581 memcpy (&o->vector, &array->vector, size);
4583 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4586 memcpy (&o->vector, &array->vector, size);
4594 * @array: the array to clone
4596 * Returns: A newly created array who is a shallow copy of @array
4599 mono_array_clone (MonoArray *array)
4601 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4604 /* helper macros to check for overflow when calculating the size of arrays */
4605 #ifdef MONO_BIG_ARRAYS
4606 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4607 #define MYGUINT_MAX MYGUINT64_MAX
4608 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4609 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4610 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4611 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4612 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4614 #define MYGUINT32_MAX 4294967295U
4615 #define MYGUINT_MAX MYGUINT32_MAX
4616 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4617 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4618 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4619 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4620 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4624 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4628 byte_len = mono_array_element_size (class);
4629 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4632 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4634 byte_len += sizeof (MonoArray);
4642 * mono_array_new_full:
4643 * @domain: domain where the object is created
4644 * @array_class: array class
4645 * @lengths: lengths for each dimension in the array
4646 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4648 * This routine creates a new array objects with the given dimensions,
4649 * lower bounds and type.
4652 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4654 uintptr_t byte_len, len, bounds_size;
4657 MonoArrayBounds *bounds;
4661 if (!array_class->inited)
4662 mono_class_init (array_class);
4666 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4667 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4669 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4673 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4675 for (i = 0; i < array_class->rank; ++i) {
4676 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4678 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4679 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4684 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4685 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4689 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4690 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4691 byte_len = (byte_len + 3) & ~3;
4692 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4693 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4694 byte_len += bounds_size;
4697 * Following three lines almost taken from mono_object_new ():
4698 * they need to be kept in sync.
4700 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4701 #ifndef HAVE_SGEN_GC
4702 if (!array_class->has_references) {
4703 o = mono_object_allocate_ptrfree (byte_len, vtable);
4704 #if NEED_TO_ZERO_PTRFREE
4705 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4707 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4708 o = mono_object_allocate_spec (byte_len, vtable);
4710 o = mono_object_allocate (byte_len, vtable);
4713 array = (MonoArray*)o;
4714 array->max_length = len;
4717 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4718 array->bounds = bounds;
4722 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4724 o = mono_gc_alloc_vector (vtable, byte_len, len);
4725 array = (MonoArray*)o;
4726 mono_stats.new_object_count++;
4728 bounds = array->bounds;
4732 for (i = 0; i < array_class->rank; ++i) {
4733 bounds [i].length = lengths [i];
4735 bounds [i].lower_bound = lower_bounds [i];
4739 if (G_UNLIKELY (profile_allocs))
4740 mono_profiler_allocation (o, array_class);
4747 * @domain: domain where the object is created
4748 * @eclass: element class
4749 * @n: number of array elements
4751 * This routine creates a new szarray with @n elements of type @eclass.
4754 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4758 MONO_ARCH_SAVE_REGS;
4760 ac = mono_array_class_get (eclass, 1);
4763 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4767 * mono_array_new_specific:
4768 * @vtable: a vtable in the appropriate domain for an initialized class
4769 * @n: number of array elements
4771 * This routine is a fast alternative to mono_array_new() for code which
4772 * can be sure about the domain it operates in.
4775 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4781 MONO_ARCH_SAVE_REGS;
4783 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4788 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4789 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4792 #ifndef HAVE_SGEN_GC
4793 if (!vtable->klass->has_references) {
4794 o = mono_object_allocate_ptrfree (byte_len, vtable);
4795 #if NEED_TO_ZERO_PTRFREE
4796 ((MonoArray*)o)->bounds = NULL;
4797 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4799 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4800 o = mono_object_allocate_spec (byte_len, vtable);
4802 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4803 o = mono_object_allocate (byte_len, vtable);
4806 ao = (MonoArray *)o;
4809 o = mono_gc_alloc_vector (vtable, byte_len, n);
4811 mono_stats.new_object_count++;
4814 if (G_UNLIKELY (profile_allocs))
4815 mono_profiler_allocation (o, vtable->klass);
4821 * mono_string_new_utf16:
4822 * @text: a pointer to an utf16 string
4823 * @len: the length of the string
4825 * Returns: A newly created string object which contains @text.
4828 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4832 s = mono_string_new_size (domain, len);
4833 g_assert (s != NULL);
4835 memcpy (mono_string_chars (s), text, len * 2);
4841 * mono_string_new_size:
4842 * @text: a pointer to an utf16 string
4843 * @len: the length of the string
4845 * Returns: A newly created string object of @len
4848 mono_string_new_size (MonoDomain *domain, gint32 len)
4852 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4854 /* overflow ? can't fit it, can't allocate it! */
4856 mono_gc_out_of_memory (-1);
4858 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4861 #ifndef HAVE_SGEN_GC
4862 s = mono_object_allocate_ptrfree (size, vtable);
4866 s = mono_gc_alloc_string (vtable, size, len);
4868 #if NEED_TO_ZERO_PTRFREE
4871 if (G_UNLIKELY (profile_allocs))
4872 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4878 * mono_string_new_len:
4879 * @text: a pointer to an utf8 string
4880 * @length: number of bytes in @text to consider
4882 * Returns: A newly created string object which contains @text.
4885 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4887 GError *error = NULL;
4888 MonoString *o = NULL;
4890 glong items_written;
4892 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4895 o = mono_string_new_utf16 (domain, ut, items_written);
4897 g_error_free (error);
4906 * @text: a pointer to an utf8 string
4908 * Returns: A newly created string object which contains @text.
4911 mono_string_new (MonoDomain *domain, const char *text)
4913 GError *error = NULL;
4914 MonoString *o = NULL;
4916 glong items_written;
4921 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4924 o = mono_string_new_utf16 (domain, ut, items_written);
4926 g_error_free (error);
4929 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4934 MonoString *o = NULL;
4936 if (!g_utf8_validate (text, -1, &end))
4939 len = g_utf8_strlen (text, -1);
4940 o = mono_string_new_size (domain, len);
4941 str = mono_string_chars (o);
4943 while (text < end) {
4944 *str++ = g_utf8_get_char (text);
4945 text = g_utf8_next_char (text);
4952 * mono_string_new_wrapper:
4953 * @text: pointer to utf8 characters.
4955 * Helper function to create a string object from @text in the current domain.
4958 mono_string_new_wrapper (const char *text)
4960 MonoDomain *domain = mono_domain_get ();
4962 MONO_ARCH_SAVE_REGS;
4965 return mono_string_new (domain, text);
4972 * @class: the class of the value
4973 * @value: a pointer to the unboxed data
4975 * Returns: A newly created object which contains @value.
4978 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4984 g_assert (class->valuetype);
4985 if (mono_class_is_nullable (class))
4986 return mono_nullable_box (value, class);
4988 vtable = mono_class_vtable (domain, class);
4991 size = mono_class_instance_size (class);
4992 res = mono_object_new_alloc_specific (vtable);
4993 if (G_UNLIKELY (profile_allocs))
4994 mono_profiler_allocation (res, class);
4996 size = size - sizeof (MonoObject);
4999 g_assert (size == mono_class_value_size (class, NULL));
5000 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5002 #if NO_UNALIGNED_ACCESS
5003 memcpy ((char *)res + sizeof (MonoObject), value, size);
5007 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5010 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5013 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5016 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5019 memcpy ((char *)res + sizeof (MonoObject), value, size);
5023 if (class->has_finalize)
5024 mono_object_register_finalizer (res);
5030 * @dest: destination pointer
5031 * @src: source pointer
5032 * @klass: a valuetype class
5034 * Copy a valuetype from @src to @dest. This function must be used
5035 * when @klass contains references fields.
5038 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5040 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5044 * mono_value_copy_array:
5045 * @dest: destination array
5046 * @dest_idx: index in the @dest array
5047 * @src: source pointer
5048 * @count: number of items
5050 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5051 * This function must be used when @klass contains references fields.
5052 * Overlap is handled.
5055 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5057 int size = mono_array_element_size (dest->obj.vtable->klass);
5058 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5059 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5060 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5064 * mono_object_get_domain:
5065 * @obj: object to query
5067 * Returns: the MonoDomain where the object is hosted
5070 mono_object_get_domain (MonoObject *obj)
5072 return mono_object_domain (obj);
5076 * mono_object_get_class:
5077 * @obj: object to query
5079 * Returns: the MonOClass of the object.
5082 mono_object_get_class (MonoObject *obj)
5084 return mono_object_class (obj);
5087 * mono_object_get_size:
5088 * @o: object to query
5090 * Returns: the size, in bytes, of @o
5093 mono_object_get_size (MonoObject* o)
5095 MonoClass* klass = mono_object_class (o);
5096 if (klass == mono_defaults.string_class) {
5097 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5098 } else if (o->vtable->rank) {
5099 MonoArray *array = (MonoArray*)o;
5100 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5101 if (array->bounds) {
5104 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5108 return mono_class_instance_size (klass);
5113 * mono_object_unbox:
5114 * @obj: object to unbox
5116 * Returns: a pointer to the start of the valuetype boxed in this
5119 * This method will assert if the object passed is not a valuetype.
5122 mono_object_unbox (MonoObject *obj)
5124 /* add assert for valuetypes? */
5125 g_assert (obj->vtable->klass->valuetype);
5126 return ((char*)obj) + sizeof (MonoObject);
5130 * mono_object_isinst:
5132 * @klass: a pointer to a class
5134 * Returns: @obj if @obj is derived from @klass
5137 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5140 mono_class_init (klass);
5142 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5143 return mono_object_isinst_mbyref (obj, klass);
5148 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5152 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5161 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5162 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5166 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5167 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5170 MonoClass *oklass = vt->klass;
5171 if ((oklass == mono_defaults.transparent_proxy_class))
5172 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5174 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5178 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5180 MonoDomain *domain = mono_domain_get ();
5182 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5183 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5184 MonoMethod *im = NULL;
5187 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5188 im = mono_object_get_virtual_method (rp, im);
5191 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5194 res = mono_runtime_invoke (im, rp, pa, NULL);
5196 if (*(MonoBoolean *) mono_object_unbox(res)) {
5197 /* Update the vtable of the remote type, so it can safely cast to this new type */
5198 mono_upgrade_remote_class (domain, obj, klass);
5207 * mono_object_castclass_mbyref:
5209 * @klass: a pointer to a class
5211 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5214 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5216 if (!obj) return NULL;
5217 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5219 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5221 "InvalidCastException"));
5226 MonoDomain *orig_domain;
5232 str_lookup (MonoDomain *domain, gpointer user_data)
5234 LDStrInfo *info = user_data;
5235 if (info->res || domain == info->orig_domain)
5237 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5243 mono_string_get_pinned (MonoString *str)
5247 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5248 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5250 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5251 news->length = mono_string_length (str);
5257 #define mono_string_get_pinned(str) (str)
5261 mono_string_is_interned_lookup (MonoString *str, int insert)
5263 MonoGHashTable *ldstr_table;
5267 domain = ((MonoObject *)str)->vtable->domain;
5268 ldstr_table = domain->ldstr_table;
5270 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5275 str = mono_string_get_pinned (str);
5277 mono_g_hash_table_insert (ldstr_table, str, str);
5281 LDStrInfo ldstr_info;
5282 ldstr_info.orig_domain = domain;
5283 ldstr_info.ins = str;
5284 ldstr_info.res = NULL;
5286 mono_domain_foreach (str_lookup, &ldstr_info);
5287 if (ldstr_info.res) {
5289 * the string was already interned in some other domain:
5290 * intern it in the current one as well.
5292 mono_g_hash_table_insert (ldstr_table, str, str);
5302 * mono_string_is_interned:
5303 * @o: String to probe
5305 * Returns whether the string has been interned.
5308 mono_string_is_interned (MonoString *o)
5310 return mono_string_is_interned_lookup (o, FALSE);
5314 * mono_string_intern:
5315 * @o: String to intern
5317 * Interns the string passed.
5318 * Returns: The interned string.
5321 mono_string_intern (MonoString *str)
5323 return mono_string_is_interned_lookup (str, TRUE);
5328 * @domain: the domain where the string will be used.
5329 * @image: a metadata context
5330 * @idx: index into the user string table.
5332 * Implementation for the ldstr opcode.
5333 * Returns: a loaded string from the @image/@idx combination.
5336 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5338 MONO_ARCH_SAVE_REGS;
5340 if (image->dynamic) {
5341 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5344 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5345 return NULL; /*FIXME we should probably be raising an exception here*/
5346 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5351 * mono_ldstr_metadata_sig
5352 * @domain: the domain for the string
5353 * @sig: the signature of a metadata string
5355 * Returns: a MonoString for a string stored in the metadata
5358 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5360 const char *str = sig;
5361 MonoString *o, *interned;
5364 len2 = mono_metadata_decode_blob_size (str, &str);
5367 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5368 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5371 guint16 *p2 = (guint16*)mono_string_chars (o);
5372 for (i = 0; i < len2; ++i) {
5373 *p2 = GUINT16_FROM_LE (*p2);
5379 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5381 /* o will get garbage collected */
5385 o = mono_string_get_pinned (o);
5387 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5394 * mono_string_to_utf8:
5395 * @s: a System.String
5397 * Returns the UTF8 representation for @s.
5398 * The resulting buffer needs to be freed with mono_free().
5400 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5403 mono_string_to_utf8 (MonoString *s)
5406 char *result = mono_string_to_utf8_checked (s, &error);
5408 if (!mono_error_ok (&error))
5409 mono_error_raise_exception (&error);
5414 * mono_string_to_utf8_checked:
5415 * @s: a System.String
5416 * @error: a MonoError.
5418 * Converts a MonoString to its UTF8 representation. May fail; check
5419 * @error to determine whether the conversion was successful.
5420 * The resulting buffer should be freed with mono_free().
5423 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5427 GError *gerror = NULL;
5429 mono_error_init (error);
5435 return g_strdup ("");
5437 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5439 mono_error_set_argument (error, "string", "%s", gerror->message);
5440 g_error_free (gerror);
5443 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5444 if (s->length > written) {
5445 /* allocate the total length and copy the part of the string that has been converted */
5446 char *as2 = g_malloc0 (s->length);
5447 memcpy (as2, as, written);
5456 * mono_string_to_utf8_ignore:
5459 * Converts a MonoString to its UTF8 representation. Will ignore
5460 * invalid surrogate pairs.
5461 * The resulting buffer should be freed with mono_free().
5465 mono_string_to_utf8_ignore (MonoString *s)
5474 return g_strdup ("");
5476 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5478 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5479 if (s->length > written) {
5480 /* allocate the total length and copy the part of the string that has been converted */
5481 char *as2 = g_malloc0 (s->length);
5482 memcpy (as2, as, written);
5491 * mono_string_to_utf8_image_ignore:
5492 * @s: a System.String
5494 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5497 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5499 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5503 * mono_string_to_utf8_mp_ignore:
5504 * @s: a System.String
5506 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5509 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5511 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5516 * mono_string_to_utf16:
5519 * Return an null-terminated array of the utf-16 chars
5520 * contained in @s. The result must be freed with g_free().
5521 * This is a temporary helper until our string implementation
5522 * is reworked to always include the null terminating char.
5525 mono_string_to_utf16 (MonoString *s)
5532 as = g_malloc ((s->length * 2) + 2);
5533 as [(s->length * 2)] = '\0';
5534 as [(s->length * 2) + 1] = '\0';
5537 return (gunichar2 *)(as);
5540 memcpy (as, mono_string_chars(s), s->length * 2);
5541 return (gunichar2 *)(as);
5545 * mono_string_from_utf16:
5546 * @data: the UTF16 string (LPWSTR) to convert
5548 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5550 * Returns: a MonoString.
5553 mono_string_from_utf16 (gunichar2 *data)
5555 MonoDomain *domain = mono_domain_get ();
5561 while (data [len]) len++;
5563 return mono_string_new_utf16 (domain, data, len);
5568 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5575 r = mono_string_to_utf8_ignore (s);
5577 r = mono_string_to_utf8_checked (s, error);
5578 if (!mono_error_ok (error))
5585 len = strlen (r) + 1;
5587 mp_s = mono_mempool_alloc (mp, len);
5589 mp_s = mono_image_alloc (image, len);
5591 memcpy (mp_s, r, len);
5599 * mono_string_to_utf8_image:
5600 * @s: a System.String
5602 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5605 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5607 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5611 * mono_string_to_utf8_mp:
5612 * @s: a System.String
5614 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5617 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5619 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5623 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5626 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5628 eh_callbacks = *cbs;
5631 MonoRuntimeExceptionHandlingCallbacks *
5632 mono_get_eh_callbacks (void)
5634 return &eh_callbacks;
5638 * mono_raise_exception:
5639 * @ex: exception object
5641 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5644 mono_raise_exception (MonoException *ex)
5647 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5648 * that will cause gcc to omit the function epilog, causing problems when
5649 * the JIT tries to walk the stack, since the return address on the stack
5650 * will point into the next function in the executable, not this one.
5653 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5654 MonoInternalThread *thread = mono_thread_internal_current ();
5655 g_assert (ex->object.vtable->domain == mono_domain_get ());
5656 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5659 eh_callbacks.mono_raise_exception (ex);
5663 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5665 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5666 MonoInternalThread *thread = mono_thread_internal_current ();
5667 g_assert (ex->object.vtable->domain == mono_domain_get ());
5668 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5671 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5675 * mono_wait_handle_new:
5676 * @domain: Domain where the object will be created
5677 * @handle: Handle for the wait handle
5679 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5682 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5684 MonoWaitHandle *res;
5685 gpointer params [1];
5686 static MonoMethod *handle_set;
5688 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5690 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5692 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5694 params [0] = &handle;
5695 mono_runtime_invoke (handle_set, res, params, NULL);
5701 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5703 static MonoClassField *f_os_handle;
5704 static MonoClassField *f_safe_handle;
5706 if (!f_os_handle && !f_safe_handle) {
5707 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5708 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5713 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5717 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5724 mono_runtime_capture_context (MonoDomain *domain)
5726 RuntimeInvokeFunction runtime_invoke;
5728 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5729 MonoMethod *method = mono_get_context_capture_method ();
5730 MonoMethod *wrapper;
5733 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5734 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5735 domain->capture_context_method = mono_compile_method (method);
5738 runtime_invoke = domain->capture_context_runtime_invoke;
5740 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5743 * mono_async_result_new:
5744 * @domain:domain where the object will be created.
5745 * @handle: wait handle.
5746 * @state: state to pass to AsyncResult
5747 * @data: C closure data.
5749 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5750 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5754 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5756 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5757 MonoObject *context = mono_runtime_capture_context (domain);
5758 /* we must capture the execution context from the original thread */
5760 MONO_OBJECT_SETREF (res, execution_context, context);
5761 /* note: result may be null if the flow is suppressed */
5765 MONO_OBJECT_SETREF (res, object_data, object_data);
5766 MONO_OBJECT_SETREF (res, async_state, state);
5768 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5770 res->sync_completed = FALSE;
5771 res->completed = FALSE;
5777 mono_message_init (MonoDomain *domain,
5778 MonoMethodMessage *this,
5779 MonoReflectionMethod *method,
5780 MonoArray *out_args)
5782 static MonoClass *object_array_klass;
5783 static MonoClass *byte_array_klass;
5784 static MonoClass *string_array_klass;
5785 MonoMethodSignature *sig = mono_method_signature (method->method);
5791 if (!object_array_klass) {
5794 klass = mono_array_class_get (mono_defaults.object_class, 1);
5797 mono_memory_barrier ();
5798 object_array_klass = klass;
5800 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5803 mono_memory_barrier ();
5804 byte_array_klass = klass;
5806 klass = mono_array_class_get (mono_defaults.string_class, 1);
5809 mono_memory_barrier ();
5810 string_array_klass = klass;
5813 MONO_OBJECT_SETREF (this, method, method);
5815 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5816 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5817 this->async_result = NULL;
5818 this->call_type = CallType_Sync;
5820 names = g_new (char *, sig->param_count);
5821 mono_method_get_param_names (method->method, (const char **) names);
5822 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5824 for (i = 0; i < sig->param_count; i++) {
5825 name = mono_string_new (domain, names [i]);
5826 mono_array_setref (this->names, i, name);
5830 for (i = 0, j = 0; i < sig->param_count; i++) {
5831 if (sig->params [i]->byref) {
5833 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5834 mono_array_setref (this->args, i, arg);
5838 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5842 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5845 mono_array_set (this->arg_types, guint8, i, arg_type);
5850 * mono_remoting_invoke:
5851 * @real_proxy: pointer to a RealProxy object
5852 * @msg: The MonoMethodMessage to execute
5853 * @exc: used to store exceptions
5854 * @out_args: used to store output arguments
5856 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5857 * IMessage interface and it is not trivial to extract results from there. So
5858 * we call an helper method PrivateInvoke instead of calling
5859 * RealProxy::Invoke() directly.
5861 * Returns: the result object.
5864 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5865 MonoObject **exc, MonoArray **out_args)
5867 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5870 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5873 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5875 real_proxy->vtable->domain->private_invoke_method = im;
5878 pa [0] = real_proxy;
5883 return mono_runtime_invoke (im, NULL, pa, exc);
5887 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5888 MonoObject **exc, MonoArray **out_args)
5890 static MonoClass *object_array_klass;
5893 MonoMethodSignature *sig;
5895 int i, j, outarg_count = 0;
5897 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5899 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5900 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5901 target = tp->rp->unwrapped_server;
5903 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5907 domain = mono_domain_get ();
5908 method = msg->method->method;
5909 sig = mono_method_signature (method);
5911 for (i = 0; i < sig->param_count; i++) {
5912 if (sig->params [i]->byref)
5916 if (!object_array_klass) {
5919 klass = mono_array_class_get (mono_defaults.object_class, 1);
5922 mono_memory_barrier ();
5923 object_array_klass = klass;
5926 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5927 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5930 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5932 for (i = 0, j = 0; i < sig->param_count; i++) {
5933 if (sig->params [i]->byref) {
5935 arg = mono_array_get (msg->args, gpointer, i);
5936 mono_array_setref (*out_args, j, arg);
5945 * mono_object_to_string:
5947 * @exc: Any exception thrown by ToString (). May be NULL.
5949 * Returns: the result of calling ToString () on an object.
5952 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5954 static MonoMethod *to_string = NULL;
5960 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5962 method = mono_object_get_virtual_method (obj, to_string);
5964 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5968 * mono_print_unhandled_exception:
5969 * @exc: The exception
5971 * Prints the unhandled exception.
5974 mono_print_unhandled_exception (MonoObject *exc)
5977 char *message = (char*)"";
5978 gboolean free_message = FALSE;
5981 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5982 message = g_strdup ("OutOfMemoryException");
5984 str = mono_object_to_string (exc, NULL);
5986 message = mono_string_to_utf8_checked (str, &error);
5987 if (!mono_error_ok (&error)) {
5988 mono_error_cleanup (&error);
5989 message = (char *) "";
5991 free_message = TRUE;
5997 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5998 * exc->vtable->klass->name, message);
6000 g_printerr ("\nUnhandled Exception: %s\n", message);
6007 * mono_delegate_ctor:
6008 * @this: pointer to an uninitialized delegate object
6009 * @target: target object
6010 * @addr: pointer to native code
6013 * Initialize a delegate and sets a specific method, not the one
6014 * associated with addr. This is useful when sharing generic code.
6015 * In that case addr will most probably not be associated with the
6016 * correct instantiation of the method.
6019 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6021 MonoDelegate *delegate = (MonoDelegate *)this;
6028 delegate->method = method;
6030 class = this->vtable->klass;
6031 mono_stats.delegate_creations++;
6033 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6035 method = mono_marshal_get_remoting_invoke (method);
6036 delegate->method_ptr = mono_compile_method (method);
6037 MONO_OBJECT_SETREF (delegate, target, target);
6038 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6039 method = mono_marshal_get_unbox_wrapper (method);
6040 delegate->method_ptr = mono_compile_method (method);
6041 MONO_OBJECT_SETREF (delegate, target, target);
6043 delegate->method_ptr = addr;
6044 MONO_OBJECT_SETREF (delegate, target, target);
6047 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6051 * mono_delegate_ctor:
6052 * @this: pointer to an uninitialized delegate object
6053 * @target: target object
6054 * @addr: pointer to native code
6056 * This is used to initialize a delegate.
6059 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6061 MonoDomain *domain = mono_domain_get ();
6063 MonoMethod *method = NULL;
6067 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6068 method = ji->method;
6069 g_assert (!method->klass->generic_container);
6072 mono_delegate_ctor_with_method (this, target, addr, method);
6076 * mono_method_call_message_new:
6077 * @method: method to encapsulate
6078 * @params: parameters to the method
6079 * @invoke: optional, delegate invoke.
6080 * @cb: async callback delegate.
6081 * @state: state passed to the async callback.
6083 * Translates arguments pointers into a MonoMethodMessage.
6086 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6087 MonoDelegate **cb, MonoObject **state)
6089 MonoDomain *domain = mono_domain_get ();
6090 MonoMethodSignature *sig = mono_method_signature (method);
6091 MonoMethodMessage *msg;
6094 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6097 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6098 count = sig->param_count - 2;
6100 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6101 count = sig->param_count;
6104 for (i = 0; i < count; i++) {
6109 if (sig->params [i]->byref)
6110 vpos = *((gpointer *)params [i]);
6114 type = sig->params [i]->type;
6115 class = mono_class_from_mono_type (sig->params [i]);
6117 if (class->valuetype)
6118 arg = mono_value_box (domain, class, vpos);
6120 arg = *((MonoObject **)vpos);
6122 mono_array_setref (msg->args, i, arg);
6125 if (cb != NULL && state != NULL) {
6126 *cb = *((MonoDelegate **)params [i]);
6128 *state = *((MonoObject **)params [i]);
6135 * mono_method_return_message_restore:
6137 * Restore results from message based processing back to arguments pointers
6140 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6142 MonoMethodSignature *sig = mono_method_signature (method);
6143 int i, j, type, size, out_len;
6145 if (out_args == NULL)
6147 out_len = mono_array_length (out_args);
6151 for (i = 0, j = 0; i < sig->param_count; i++) {
6152 MonoType *pt = sig->params [i];
6157 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6159 arg = mono_array_get (out_args, gpointer, j);
6162 g_assert (type != MONO_TYPE_VOID);
6164 if (MONO_TYPE_IS_REFERENCE (pt)) {
6165 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6168 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6169 size = mono_class_value_size (class, NULL);
6170 if (class->has_references)
6171 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6173 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6175 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6176 memset (*((gpointer *)params [i]), 0, size);
6186 * mono_load_remote_field:
6187 * @this: pointer to an object
6188 * @klass: klass of the object containing @field
6189 * @field: the field to load
6190 * @res: a storage to store the result
6192 * This method is called by the runtime on attempts to load fields of
6193 * transparent proxy objects. @this points to such TP, @klass is the class of
6194 * the object containing @field. @res is a storage location which can be
6195 * used to store the result.
6197 * Returns: an address pointing to the value of field.
6200 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6202 static MonoMethod *getter = NULL;
6203 MonoDomain *domain = mono_domain_get ();
6204 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6205 MonoClass *field_class;
6206 MonoMethodMessage *msg;
6207 MonoArray *out_args;
6211 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6212 g_assert (res != NULL);
6214 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6215 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6220 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6224 field_class = mono_class_from_mono_type (field->type);
6226 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6227 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6228 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6230 full_name = mono_type_get_full_name (klass);
6231 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6232 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6235 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6237 if (exc) mono_raise_exception ((MonoException *)exc);
6239 if (mono_array_length (out_args) == 0)
6242 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6244 if (field_class->valuetype) {
6245 return ((char *)*res) + sizeof (MonoObject);
6251 * mono_load_remote_field_new:
6256 * Missing documentation.
6259 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6261 static MonoMethod *getter = NULL;
6262 MonoDomain *domain = mono_domain_get ();
6263 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6264 MonoClass *field_class;
6265 MonoMethodMessage *msg;
6266 MonoArray *out_args;
6267 MonoObject *exc, *res;
6270 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6272 field_class = mono_class_from_mono_type (field->type);
6274 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6276 if (field_class->valuetype) {
6277 res = mono_object_new (domain, field_class);
6278 val = ((gchar *) res) + sizeof (MonoObject);
6282 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6287 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6291 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6292 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6294 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6296 full_name = mono_type_get_full_name (klass);
6297 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6298 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6301 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6303 if (exc) mono_raise_exception ((MonoException *)exc);
6305 if (mono_array_length (out_args) == 0)
6308 res = mono_array_get (out_args, MonoObject *, 0);
6314 * mono_store_remote_field:
6315 * @this: pointer to an object
6316 * @klass: klass of the object containing @field
6317 * @field: the field to load
6318 * @val: the value/object to store
6320 * This method is called by the runtime on attempts to store fields of
6321 * transparent proxy objects. @this points to such TP, @klass is the class of
6322 * the object containing @field. @val is the new value to store in @field.
6325 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6327 static MonoMethod *setter = NULL;
6328 MonoDomain *domain = mono_domain_get ();
6329 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6330 MonoClass *field_class;
6331 MonoMethodMessage *msg;
6332 MonoArray *out_args;
6337 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6339 field_class = mono_class_from_mono_type (field->type);
6341 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6342 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6343 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6348 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6352 if (field_class->valuetype)
6353 arg = mono_value_box (domain, field_class, val);
6355 arg = *((MonoObject **)val);
6358 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6359 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6361 full_name = mono_type_get_full_name (klass);
6362 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6363 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6364 mono_array_setref (msg->args, 2, arg);
6367 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6369 if (exc) mono_raise_exception ((MonoException *)exc);
6373 * mono_store_remote_field_new:
6379 * Missing documentation
6382 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6384 static MonoMethod *setter = NULL;
6385 MonoDomain *domain = mono_domain_get ();
6386 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6387 MonoClass *field_class;
6388 MonoMethodMessage *msg;
6389 MonoArray *out_args;
6393 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6395 field_class = mono_class_from_mono_type (field->type);
6397 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6398 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6399 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6404 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6408 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6409 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6411 full_name = mono_type_get_full_name (klass);
6412 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6413 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6414 mono_array_setref (msg->args, 2, arg);
6417 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6419 if (exc) mono_raise_exception ((MonoException *)exc);
6423 * mono_create_ftnptr:
6425 * Given a function address, create a function descriptor for it.
6426 * This is only needed on some platforms.
6429 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6431 return callbacks.create_ftnptr (domain, addr);
6435 * mono_get_addr_from_ftnptr:
6437 * Given a pointer to a function descriptor, return the function address.
6438 * This is only needed on some platforms.
6441 mono_get_addr_from_ftnptr (gpointer descr)
6443 return callbacks.get_addr_from_ftnptr (descr);
6447 * mono_string_chars:
6450 * Returns a pointer to the UCS16 characters stored in the MonoString
6453 mono_string_chars (MonoString *s)
6459 * mono_string_length:
6462 * Returns the lenght in characters of the string
6465 mono_string_length (MonoString *s)
6471 * mono_array_length:
6472 * @array: a MonoArray*
6474 * Returns the total number of elements in the array. This works for
6475 * both vectors and multidimensional arrays.
6478 mono_array_length (MonoArray *array)
6480 return array->max_length;
6484 * mono_array_addr_with_size:
6485 * @array: a MonoArray*
6486 * @size: size of the array elements
6487 * @idx: index into the array
6489 * Returns the address of the @idx element in the array.
6492 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6494 return ((char*)(array)->vector) + size * idx;