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);
85 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
86 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
87 static CRITICAL_SECTION ldstr_section;
89 static gboolean profile_allocs = TRUE;
92 mono_runtime_object_init (MonoObject *this)
94 MonoMethod *method = NULL;
95 MonoClass *klass = this->vtable->klass;
97 method = mono_class_get_method_from_name (klass, ".ctor", 0);
100 if (method->klass->valuetype)
101 this = mono_object_unbox (this);
102 mono_runtime_invoke (method, this, NULL, NULL);
105 /* The pseudo algorithm for type initialization from the spec
106 Note it doesn't say anything about domains - only threads.
108 2. If the type is initialized you are done.
109 2.1. If the type is not yet initialized, try to take an
111 2.2. If successful, record this thread as responsible for
112 initializing the type and proceed to step 2.3.
113 2.2.1. If not, see whether this thread or any thread
114 waiting for this thread to complete already holds the lock.
115 2.2.2. If so, return since blocking would create a deadlock. This thread
116 will now see an incompletely initialized state for the type,
117 but no deadlock will arise.
118 2.2.3 If not, block until the type is initialized then return.
119 2.3 Initialize the parent type and then all interfaces implemented
121 2.4 Execute the type initialization code for this type.
122 2.5 Mark the type as initialized, release the initialization lock,
123 awaken any threads waiting for this type to be initialized,
130 guint32 initializing_tid;
131 guint32 waiting_count;
133 CRITICAL_SECTION initialization_section;
134 } TypeInitializationLock;
136 /* for locking access to type_initialization_hash and blocked_thread_hash */
137 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
138 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
139 static CRITICAL_SECTION type_initialization_section;
141 /* from vtable to lock */
142 static GHashTable *type_initialization_hash;
144 /* from thread id to thread id being waited on */
145 static GHashTable *blocked_thread_hash;
148 static MonoThread *main_thread;
150 /* Functions supplied by the runtime */
151 static MonoRuntimeCallbacks callbacks;
154 * mono_thread_set_main:
155 * @thread: thread to set as the main thread
157 * This function can be used to instruct the runtime to treat @thread
158 * as the main thread, ie, the thread that would normally execute the Main()
159 * method. This basically means that at the end of @thread, the runtime will
160 * wait for the existing foreground threads to quit and other such details.
163 mono_thread_set_main (MonoThread *thread)
165 main_thread = thread;
169 mono_thread_get_main (void)
175 mono_type_initialization_init (void)
177 InitializeCriticalSection (&type_initialization_section);
178 type_initialization_hash = g_hash_table_new (NULL, NULL);
179 blocked_thread_hash = g_hash_table_new (NULL, NULL);
180 InitializeCriticalSection (&ldstr_section);
184 mono_type_initialization_cleanup (void)
187 /* This is causing race conditions with
188 * mono_release_type_locks
190 DeleteCriticalSection (&type_initialization_section);
191 g_hash_table_destroy (type_initialization_hash);
192 type_initialization_hash = NULL;
194 DeleteCriticalSection (&ldstr_section);
195 g_hash_table_destroy (blocked_thread_hash);
196 blocked_thread_hash = NULL;
202 * get_type_init_exception_for_vtable:
204 * Return the stored type initialization exception for VTABLE.
206 static MonoException*
207 get_type_init_exception_for_vtable (MonoVTable *vtable)
209 MonoDomain *domain = vtable->domain;
210 MonoClass *klass = vtable->klass;
214 g_assert (vtable->init_failed);
217 * If the initializing thread was rudely aborted, the exception is not stored
221 mono_domain_lock (domain);
222 if (domain->type_init_exception_hash)
223 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
224 mono_domain_unlock (domain);
227 if (klass->name_space && *klass->name_space)
228 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
230 full_name = g_strdup (klass->name);
231 ex = mono_get_exception_type_initialization (full_name, NULL);
238 * mono_runtime_class_init:
239 * @vtable: vtable that needs to be initialized
241 * This routine calls the class constructor for @vtable.
244 mono_runtime_class_init (MonoVTable *vtable)
246 mono_runtime_class_init_full (vtable, TRUE);
250 * mono_runtime_class_init_full:
251 * @vtable that neeeds to be initialized
252 * @raise_exception is TRUE, exceptions are raised intead of returned
256 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
259 MonoException *exc_to_throw;
260 MonoMethod *method = NULL;
266 if (vtable->initialized)
270 klass = vtable->klass;
272 if (!klass->image->checked_module_cctor) {
273 mono_image_check_for_module_cctor (klass->image);
274 if (klass->image->has_module_cctor) {
275 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
276 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
279 mono_runtime_class_init (module_vtable);
282 method = mono_class_get_cctor (klass);
285 MonoDomain *domain = vtable->domain;
286 TypeInitializationLock *lock;
287 guint32 tid = GetCurrentThreadId();
288 int do_initialization = 0;
289 MonoDomain *last_domain = NULL;
291 mono_type_initialization_lock ();
292 /* double check... */
293 if (vtable->initialized) {
294 mono_type_initialization_unlock ();
297 if (vtable->init_failed) {
298 mono_type_initialization_unlock ();
300 /* The type initialization already failed once, rethrow the same exception */
302 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
303 return get_type_init_exception_for_vtable (vtable);
305 lock = g_hash_table_lookup (type_initialization_hash, vtable);
307 /* This thread will get to do the initialization */
308 if (mono_domain_get () != domain) {
309 /* Transfer into the target domain */
310 last_domain = mono_domain_get ();
311 if (!mono_domain_set (domain, FALSE)) {
312 vtable->initialized = 1;
313 mono_type_initialization_unlock ();
315 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
316 return mono_get_exception_appdomain_unloaded ();
319 lock = g_malloc (sizeof(TypeInitializationLock));
320 InitializeCriticalSection (&lock->initialization_section);
321 lock->initializing_tid = tid;
322 lock->waiting_count = 1;
324 /* grab the vtable lock while this thread still owns type_initialization_section */
325 EnterCriticalSection (&lock->initialization_section);
326 g_hash_table_insert (type_initialization_hash, vtable, lock);
327 do_initialization = 1;
330 TypeInitializationLock *pending_lock;
332 if (lock->initializing_tid == tid || lock->done) {
333 mono_type_initialization_unlock ();
336 /* see if the thread doing the initialization is already blocked on this thread */
337 blocked = GUINT_TO_POINTER (lock->initializing_tid);
338 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
339 if (pending_lock->initializing_tid == tid) {
340 if (!pending_lock->done) {
341 mono_type_initialization_unlock ();
344 /* the thread doing the initialization is blocked on this thread,
345 but on a lock that has already been freed. It just hasn't got
350 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
352 ++lock->waiting_count;
353 /* record the fact that we are waiting on the initializing thread */
354 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
356 mono_type_initialization_unlock ();
358 if (do_initialization) {
359 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
361 /* If the initialization failed, mark the class as unusable. */
362 /* Avoid infinite loops */
364 (klass->image == mono_defaults.corlib &&
365 !strcmp (klass->name_space, "System") &&
366 !strcmp (klass->name, "TypeInitializationException")))) {
367 vtable->init_failed = 1;
369 if (klass->name_space && *klass->name_space)
370 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
372 full_name = g_strdup (klass->name);
373 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
377 * Store the exception object so it could be thrown on subsequent
380 mono_domain_lock (domain);
381 if (!domain->type_init_exception_hash)
382 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
383 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
384 mono_domain_unlock (domain);
388 mono_domain_set (last_domain, TRUE);
390 LeaveCriticalSection (&lock->initialization_section);
392 /* this just blocks until the initializing thread is done */
393 EnterCriticalSection (&lock->initialization_section);
394 LeaveCriticalSection (&lock->initialization_section);
397 mono_type_initialization_lock ();
398 if (lock->initializing_tid != tid)
399 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
400 --lock->waiting_count;
401 if (lock->waiting_count == 0) {
402 DeleteCriticalSection (&lock->initialization_section);
403 g_hash_table_remove (type_initialization_hash, vtable);
406 if (!vtable->init_failed)
407 vtable->initialized = 1;
408 mono_type_initialization_unlock ();
410 if (vtable->init_failed) {
411 /* Either we were the initializing thread or we waited for the initialization */
413 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
414 return get_type_init_exception_for_vtable (vtable);
417 vtable->initialized = 1;
424 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
426 MonoVTable *vtable = (MonoVTable*)key;
428 TypeInitializationLock *lock = (TypeInitializationLock*) value;
429 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
432 * Have to set this since it cannot be set by the normal code in
433 * mono_runtime_class_init (). In this case, the exception object is not stored,
434 * and get_type_init_exception_for_class () needs to be aware of this.
436 vtable->init_failed = 1;
437 LeaveCriticalSection (&lock->initialization_section);
438 --lock->waiting_count;
439 if (lock->waiting_count == 0) {
440 DeleteCriticalSection (&lock->initialization_section);
449 mono_release_type_locks (MonoInternalThread *thread)
451 mono_type_initialization_lock ();
452 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
453 mono_type_initialization_unlock ();
457 default_trampoline (MonoMethod *method)
463 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
465 g_assert_not_reached ();
471 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
473 g_error ("remoting not installed");
478 default_delegate_trampoline (MonoClass *klass)
480 g_assert_not_reached ();
484 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
485 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
486 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
487 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
488 static MonoImtThunkBuilder imt_thunk_builder = NULL;
489 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
490 #if (MONO_IMT_SIZE > 32)
491 #error "MONO_IMT_SIZE cannot be larger than 32"
495 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
497 memcpy (&callbacks, cbs, sizeof (*cbs));
500 MonoRuntimeCallbacks*
501 mono_get_runtime_callbacks (void)
507 mono_install_trampoline (MonoTrampoline func)
509 arch_create_jit_trampoline = func? func: default_trampoline;
513 mono_install_jump_trampoline (MonoJumpTrampoline func)
515 arch_create_jump_trampoline = func? func: default_jump_trampoline;
519 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
521 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
525 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
527 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
531 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
532 imt_thunk_builder = func;
535 static MonoCompileFunc default_mono_compile_method = NULL;
538 * mono_install_compile_method:
539 * @func: function to install
541 * This is a VM internal routine
544 mono_install_compile_method (MonoCompileFunc func)
546 default_mono_compile_method = func;
550 * mono_compile_method:
551 * @method: The method to compile.
553 * This JIT-compiles the method, and returns the pointer to the native code
557 mono_compile_method (MonoMethod *method)
559 if (!default_mono_compile_method) {
560 g_error ("compile method called on uninitialized runtime");
563 return default_mono_compile_method (method);
567 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
569 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
573 mono_runtime_create_delegate_trampoline (MonoClass *klass)
575 return arch_create_delegate_trampoline (klass);
578 static MonoFreeMethodFunc default_mono_free_method = NULL;
581 * mono_install_free_method:
582 * @func: pointer to the MonoFreeMethodFunc used to release a method
584 * This is an internal VM routine, it is used for the engines to
585 * register a handler to release the resources associated with a method.
587 * Methods are freed when no more references to the delegate that holds
591 mono_install_free_method (MonoFreeMethodFunc func)
593 default_mono_free_method = func;
597 * mono_runtime_free_method:
598 * @domain; domain where the method is hosted
599 * @method: method to release
601 * This routine is invoked to free the resources associated with
602 * a method that has been JIT compiled. This is used to discard
603 * methods that were used only temporarily (for example, used in marshalling)
607 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
609 if (default_mono_free_method != NULL)
610 default_mono_free_method (domain, method);
612 mono_method_clear_object (domain, method);
614 mono_free_method (method);
618 * The vtables in the root appdomain are assumed to be reachable by other
619 * roots, and we don't use typed allocation in the other domains.
622 /* The sync block is no longer a GC pointer */
623 #define GC_HEADER_BITMAP (0)
625 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
628 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
630 MonoClassField *field;
636 max_size = mono_class_data_size (class) / sizeof (gpointer);
638 max_size = class->instance_size / sizeof (gpointer);
639 if (max_size > size) {
640 g_assert (offset <= 0);
641 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
646 /*An Ephemeron cannot be marked by sgen*/
647 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
649 memset (bitmap, 0, size / 8);
654 for (p = class; p != NULL; p = p->parent) {
655 gpointer iter = NULL;
656 while ((field = mono_class_get_fields (p, &iter))) {
660 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
662 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
665 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
668 /* FIXME: should not happen, flag as type load error */
669 if (field->type->byref)
672 if (static_fields && field->offset == -1)
676 pos = field->offset / sizeof (gpointer);
679 type = mono_type_get_underlying_type (field->type);
680 switch (type->type) {
683 case MONO_TYPE_FNPTR:
685 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
690 if (class->image != mono_defaults.corlib)
693 case MONO_TYPE_STRING:
694 case MONO_TYPE_SZARRAY:
695 case MONO_TYPE_CLASS:
696 case MONO_TYPE_OBJECT:
697 case MONO_TYPE_ARRAY:
698 g_assert ((field->offset % sizeof(gpointer)) == 0);
700 g_assert (pos < size || pos <= max_size);
701 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
702 *max_set = MAX (*max_set, pos);
704 case MONO_TYPE_GENERICINST:
705 if (!mono_type_generic_inst_is_valuetype (type)) {
706 g_assert ((field->offset % sizeof(gpointer)) == 0);
708 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
709 *max_set = MAX (*max_set, pos);
714 case MONO_TYPE_VALUETYPE: {
715 MonoClass *fclass = mono_class_from_mono_type (field->type);
716 if (fclass->has_references) {
717 /* remove the object header */
718 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
732 case MONO_TYPE_BOOLEAN:
736 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
748 * similar to the above, but sets the bits in the bitmap for any non-ref field
749 * and ignores static fields
752 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
754 MonoClassField *field;
759 max_size = class->instance_size / sizeof (gpointer);
760 if (max_size >= size) {
761 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
764 for (p = class; p != NULL; p = p->parent) {
765 gpointer iter = NULL;
766 while ((field = mono_class_get_fields (p, &iter))) {
769 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
771 /* FIXME: should not happen, flag as type load error */
772 if (field->type->byref)
775 pos = field->offset / sizeof (gpointer);
778 type = mono_type_get_underlying_type (field->type);
779 switch (type->type) {
780 #if SIZEOF_VOID_P == 8
784 case MONO_TYPE_FNPTR:
789 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
790 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
791 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
794 #if SIZEOF_VOID_P == 4
798 case MONO_TYPE_FNPTR:
803 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
804 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
805 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
811 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
812 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
813 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
816 case MONO_TYPE_BOOLEAN:
819 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
821 case MONO_TYPE_STRING:
822 case MONO_TYPE_SZARRAY:
823 case MONO_TYPE_CLASS:
824 case MONO_TYPE_OBJECT:
825 case MONO_TYPE_ARRAY:
827 case MONO_TYPE_GENERICINST:
828 if (!mono_type_generic_inst_is_valuetype (type)) {
833 case MONO_TYPE_VALUETYPE: {
834 MonoClass *fclass = mono_class_from_mono_type (field->type);
835 /* remove the object header */
836 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
840 g_assert_not_reached ();
849 * mono_class_insecure_overlapping:
850 * check if a class with explicit layout has references and non-references
851 * fields overlapping.
853 * Returns: TRUE if it is insecure to load the type.
856 mono_class_insecure_overlapping (MonoClass *klass)
860 gsize default_bitmap [4] = {0};
862 gsize default_nrbitmap [4] = {0};
863 int i, insecure = FALSE;
866 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
867 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
869 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
870 int idx = i % (sizeof (bitmap [0]) * 8);
871 if (bitmap [idx] & nrbitmap [idx]) {
876 if (bitmap != default_bitmap)
878 if (nrbitmap != default_nrbitmap)
881 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
889 mono_string_alloc (int length)
891 return mono_string_new_size (mono_domain_get (), length);
895 mono_class_compute_gc_descriptor (MonoClass *class)
899 gsize default_bitmap [4] = {0};
900 static gboolean gcj_inited = FALSE;
905 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
906 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
907 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
908 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
910 #ifdef HAVE_GC_GCJ_MALLOC
912 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
916 #ifdef GC_REDIRECT_TO_LOCAL
917 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
918 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
920 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
921 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
926 mono_loader_unlock ();
930 mono_class_init (class);
932 if (class->gc_descr_inited)
935 class->gc_descr_inited = TRUE;
936 class->gc_descr = GC_NO_DESCRIPTOR;
938 bitmap = default_bitmap;
939 if (class == mono_defaults.string_class) {
940 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
941 } else if (class->rank) {
942 mono_class_compute_gc_descriptor (class->element_class);
943 if (!class->element_class->valuetype) {
945 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
946 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
947 class->name_space, class->name);*/
949 /* remove the object header */
950 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
951 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
952 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
953 class->name_space, class->name);*/
954 if (bitmap != default_bitmap)
958 /*static int count = 0;
961 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
962 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
964 if (class->gc_descr == GC_NO_DESCRIPTOR)
965 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
967 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
968 if (bitmap != default_bitmap)
974 * field_is_special_static:
975 * @fklass: The MonoClass to look up.
976 * @field: The MonoClassField describing the field.
978 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
979 * SPECIAL_STATIC_NONE otherwise.
982 field_is_special_static (MonoClass *fklass, MonoClassField *field)
984 MonoCustomAttrInfo *ainfo;
986 ainfo = mono_custom_attrs_from_field (fklass, field);
989 for (i = 0; i < ainfo->num_attrs; ++i) {
990 MonoClass *klass = ainfo->attrs [i].ctor->klass;
991 if (klass->image == mono_defaults.corlib) {
992 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
993 mono_custom_attrs_free (ainfo);
994 return SPECIAL_STATIC_THREAD;
996 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
997 mono_custom_attrs_free (ainfo);
998 return SPECIAL_STATIC_CONTEXT;
1002 mono_custom_attrs_free (ainfo);
1003 return SPECIAL_STATIC_NONE;
1006 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1007 #define mix(a,b,c) { \
1008 a -= c; a ^= rot(c, 4); c += b; \
1009 b -= a; b ^= rot(a, 6); a += c; \
1010 c -= b; c ^= rot(b, 8); b += a; \
1011 a -= c; a ^= rot(c,16); c += b; \
1012 b -= a; b ^= rot(a,19); a += c; \
1013 c -= b; c ^= rot(b, 4); b += a; \
1015 #define final(a,b,c) { \
1016 c ^= b; c -= rot(b,14); \
1017 a ^= c; a -= rot(c,11); \
1018 b ^= a; b -= rot(a,25); \
1019 c ^= b; c -= rot(b,16); \
1020 a ^= c; a -= rot(c,4); \
1021 b ^= a; b -= rot(a,14); \
1022 c ^= b; c -= rot(b,24); \
1026 * mono_method_get_imt_slot:
1028 * The IMT slot is embedded into AOTed code, so this must return the same value
1029 * for the same method across all executions. This means:
1030 * - pointers shouldn't be used as hash values.
1031 * - mono_metadata_str_hash () should be used for hashing strings.
1034 mono_method_get_imt_slot (MonoMethod *method)
1036 MonoMethodSignature *sig;
1038 guint32 *hashes_start, *hashes;
1042 /* This can be used to stress tests the collision code */
1046 * We do this to simplify generic sharing. It will hurt
1047 * performance in cases where a class implements two different
1048 * instantiations of the same generic interface.
1049 * The code in build_imt_slots () depends on this.
1051 if (method->is_inflated)
1052 method = ((MonoMethodInflated*)method)->declaring;
1054 sig = mono_method_signature (method);
1055 hashes_count = sig->param_count + 4;
1056 hashes_start = malloc (hashes_count * sizeof (guint32));
1057 hashes = hashes_start;
1059 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1060 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1061 method->klass->name_space, method->klass->name, method->name);
1062 g_assert_not_reached ();
1065 /* Initialize hashes */
1066 hashes [0] = mono_metadata_str_hash (method->klass->name);
1067 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1068 hashes [2] = mono_metadata_str_hash (method->name);
1069 hashes [3] = mono_metadata_type_hash (sig->ret);
1070 for (i = 0; i < sig->param_count; i++) {
1071 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1074 /* Setup internal state */
1075 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1077 /* Handle most of the hashes */
1078 while (hashes_count > 3) {
1087 /* Handle the last 3 hashes (all the case statements fall through) */
1088 switch (hashes_count) {
1089 case 3 : c += hashes [2];
1090 case 2 : b += hashes [1];
1091 case 1 : a += hashes [0];
1093 case 0: /* nothing left to add */
1097 free (hashes_start);
1098 /* Report the result */
1099 return c % MONO_IMT_SIZE;
1108 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1109 guint32 imt_slot = mono_method_get_imt_slot (method);
1110 MonoImtBuilderEntry *entry;
1112 if (slot_num >= 0 && imt_slot != slot_num) {
1113 /* we build just a single imt slot and this is not it */
1117 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1118 entry->key = method;
1119 entry->value.vtable_slot = vtable_slot;
1120 entry->next = imt_builder [imt_slot];
1121 if (imt_builder [imt_slot] != NULL) {
1122 entry->children = imt_builder [imt_slot]->children + 1;
1123 if (entry->children == 1) {
1124 mono_stats.imt_slots_with_collisions++;
1125 *imt_collisions_bitmap |= (1 << imt_slot);
1128 entry->children = 0;
1129 mono_stats.imt_used_slots++;
1131 imt_builder [imt_slot] = entry;
1134 char *method_name = mono_method_full_name (method, TRUE);
1135 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1136 method, method_name, imt_slot, vtable_slot, entry->children);
1137 g_free (method_name);
1144 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1146 MonoMethod *method = e->key;
1147 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1151 method->klass->name_space,
1152 method->klass->name,
1155 printf (" * %s: NULL\n", message);
1161 compare_imt_builder_entries (const void *p1, const void *p2) {
1162 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1163 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1165 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1169 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1171 int count = end - start;
1172 int chunk_start = out_array->len;
1175 for (i = start; i < end; ++i) {
1176 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1177 item->key = sorted_array [i]->key;
1178 item->value = sorted_array [i]->value;
1179 item->has_target_code = sorted_array [i]->has_target_code;
1180 item->is_equals = TRUE;
1182 item->check_target_idx = out_array->len + 1;
1184 item->check_target_idx = 0;
1185 g_ptr_array_add (out_array, item);
1188 int middle = start + count / 2;
1189 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1191 item->key = sorted_array [middle]->key;
1192 item->is_equals = FALSE;
1193 g_ptr_array_add (out_array, item);
1194 imt_emit_ir (sorted_array, start, middle, out_array);
1195 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1201 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1202 int number_of_entries = entries->children + 1;
1203 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1204 GPtrArray *result = g_ptr_array_new ();
1205 MonoImtBuilderEntry *current_entry;
1208 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1209 sorted_array [i] = current_entry;
1211 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1213 /*for (i = 0; i < number_of_entries; i++) {
1214 print_imt_entry (" sorted array:", sorted_array [i], i);
1217 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1219 free (sorted_array);
1224 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1226 if (imt_builder_entry != NULL) {
1227 if (imt_builder_entry->children == 0 && !fail_tramp) {
1228 /* No collision, return the vtable slot contents */
1229 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1231 /* Collision, build the thunk */
1232 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1235 result = imt_thunk_builder (vtable, domain,
1236 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1237 for (i = 0; i < imt_ir->len; ++i)
1238 g_free (g_ptr_array_index (imt_ir, i));
1239 g_ptr_array_free (imt_ir, TRUE);
1251 static MonoImtBuilderEntry*
1252 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1255 * LOCKING: requires the loader and domain locks.
1259 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1263 guint32 imt_collisions_bitmap = 0;
1264 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1265 int method_count = 0;
1266 gboolean record_method_count_for_max_collisions = FALSE;
1267 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1270 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1272 for (i = 0; i < klass->interface_offsets_count; ++i) {
1273 MonoClass *iface = klass->interfaces_packed [i];
1274 int interface_offset = klass->interface_offsets_packed [i];
1275 int method_slot_in_interface, vt_slot;
1277 if (mono_class_has_variant_generic_params (iface))
1278 has_variant_iface = TRUE;
1280 vt_slot = interface_offset;
1281 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1284 if (slot_num >= 0 && iface->is_inflated) {
1286 * The imt slot of the method is the same as for its declaring method,
1287 * see the comment in mono_method_get_imt_slot (), so we can
1288 * avoid inflating methods which will be discarded by
1289 * add_imt_builder_entry anyway.
1291 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1292 if (mono_method_get_imt_slot (method) != slot_num) {
1297 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1298 if (method->is_generic) {
1299 has_generic_virtual = TRUE;
1304 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1305 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1310 if (extra_interfaces) {
1311 int interface_offset = klass->vtable_size;
1313 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1314 MonoClass* iface = list_item->data;
1315 int method_slot_in_interface;
1316 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1317 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1318 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1320 interface_offset += iface->method.count;
1323 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1324 /* overwrite the imt slot only if we're building all the entries or if
1325 * we're building this specific one
1327 if (slot_num < 0 || i == slot_num) {
1328 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1331 if (imt_builder [i]) {
1332 MonoImtBuilderEntry *entry;
1334 /* Link entries with imt_builder [i] */
1335 for (entry = entries; entry->next; entry = entry->next) {
1337 MonoMethod *method = (MonoMethod*)entry->key;
1338 char *method_name = mono_method_full_name (method, TRUE);
1339 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1340 g_free (method_name);
1343 entry->next = imt_builder [i];
1344 entries->children += imt_builder [i]->children + 1;
1346 imt_builder [i] = entries;
1349 if (has_generic_virtual || has_variant_iface) {
1351 * There might be collisions later when the the thunk is expanded.
1353 imt_collisions_bitmap |= (1 << i);
1356 * The IMT thunk might be called with an instance of one of the
1357 * generic virtual methods, so has to fallback to the IMT trampoline.
1359 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1361 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1364 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1368 if (imt_builder [i] != NULL) {
1369 int methods_in_slot = imt_builder [i]->children + 1;
1370 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1371 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1372 record_method_count_for_max_collisions = TRUE;
1374 method_count += methods_in_slot;
1378 mono_stats.imt_number_of_methods += method_count;
1379 if (record_method_count_for_max_collisions) {
1380 mono_stats.imt_method_count_when_max_collisions = method_count;
1383 for (i = 0; i < MONO_IMT_SIZE; i++) {
1384 MonoImtBuilderEntry* entry = imt_builder [i];
1385 while (entry != NULL) {
1386 MonoImtBuilderEntry* next = entry->next;
1392 /* we OR the bitmap since we may build just a single imt slot at a time */
1393 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1397 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1398 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1402 * mono_vtable_build_imt_slot:
1403 * @vtable: virtual object table struct
1404 * @imt_slot: slot in the IMT table
1406 * Fill the given @imt_slot in the IMT table of @vtable with
1407 * a trampoline or a thunk for the case of collisions.
1408 * This is part of the internal mono API.
1410 * LOCKING: Take the domain lock.
1413 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1415 gpointer *imt = (gpointer*)vtable;
1416 imt -= MONO_IMT_SIZE;
1417 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1419 /* no support for extra interfaces: the proxy objects will need
1420 * to build the complete IMT
1421 * Update and heck needs to ahppen inside the proper domain lock, as all
1422 * the changes made to a MonoVTable.
1424 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1425 mono_domain_lock (vtable->domain);
1426 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1427 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1428 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1429 mono_domain_unlock (vtable->domain);
1430 mono_loader_unlock ();
1435 * The first two free list entries both belong to the wait list: The
1436 * first entry is the pointer to the head of the list and the second
1437 * entry points to the last element. That way appending and removing
1438 * the first element are both O(1) operations.
1440 #ifdef MONO_SMALL_CONFIG
1441 #define NUM_FREE_LISTS 6
1443 #define NUM_FREE_LISTS 12
1445 #define FIRST_FREE_LIST_SIZE 64
1446 #define MAX_WAIT_LENGTH 50
1447 #define THUNK_THRESHOLD 10
1450 * LOCKING: The domain lock must be held.
1453 init_thunk_free_lists (MonoDomain *domain)
1455 if (domain->thunk_free_lists)
1457 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1461 list_index_for_size (int item_size)
1464 int size = FIRST_FREE_LIST_SIZE;
1466 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1475 * mono_method_alloc_generic_virtual_thunk:
1477 * @size: size in bytes
1479 * Allocs size bytes to be used for the code of a generic virtual
1480 * thunk. It's either allocated from the domain's code manager or
1481 * reused from a previously invalidated piece.
1483 * LOCKING: The domain lock must be held.
1486 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1488 static gboolean inited = FALSE;
1489 static int generic_virtual_thunks_size = 0;
1493 MonoThunkFreeList **l;
1495 init_thunk_free_lists (domain);
1497 size += sizeof (guint32);
1498 if (size < sizeof (MonoThunkFreeList))
1499 size = sizeof (MonoThunkFreeList);
1501 i = list_index_for_size (size);
1502 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1503 if ((*l)->size >= size) {
1504 MonoThunkFreeList *item = *l;
1506 return ((guint32*)item) + 1;
1510 /* no suitable item found - search lists of larger sizes */
1511 while (++i < NUM_FREE_LISTS) {
1512 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1515 g_assert (item->size > size);
1516 domain->thunk_free_lists [i] = item->next;
1517 return ((guint32*)item) + 1;
1520 /* still nothing found - allocate it */
1522 mono_counters_register ("Generic virtual thunk bytes",
1523 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1526 generic_virtual_thunks_size += size;
1528 p = mono_domain_code_reserve (domain, size);
1535 * LOCKING: The domain lock must be held.
1538 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1541 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1543 init_thunk_free_lists (domain);
1545 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1546 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1547 int length = item->length;
1550 /* unlink the first item from the wait list */
1551 domain->thunk_free_lists [0] = item->next;
1552 domain->thunk_free_lists [0]->length = length - 1;
1554 i = list_index_for_size (item->size);
1556 /* put it in the free list */
1557 item->next = domain->thunk_free_lists [i];
1558 domain->thunk_free_lists [i] = item;
1562 if (domain->thunk_free_lists [1]) {
1563 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1564 domain->thunk_free_lists [0]->length++;
1566 g_assert (!domain->thunk_free_lists [0]);
1568 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1569 domain->thunk_free_lists [0]->length = 1;
1573 typedef struct _GenericVirtualCase {
1577 struct _GenericVirtualCase *next;
1578 } GenericVirtualCase;
1581 * get_generic_virtual_entries:
1583 * Return IMT entries for the generic virtual method instances and
1584 * variant interface methods for vtable slot
1587 static MonoImtBuilderEntry*
1588 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1590 GenericVirtualCase *list;
1591 MonoImtBuilderEntry *entries;
1593 mono_domain_lock (domain);
1594 if (!domain->generic_virtual_cases)
1595 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1597 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1600 for (; list; list = list->next) {
1601 MonoImtBuilderEntry *entry;
1603 if (list->count < THUNK_THRESHOLD)
1606 entry = g_new0 (MonoImtBuilderEntry, 1);
1607 entry->key = list->method;
1608 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1609 entry->has_target_code = 1;
1611 entry->children = entries->children + 1;
1612 entry->next = entries;
1616 mono_domain_unlock (domain);
1618 /* FIXME: Leaking memory ? */
1623 * mono_method_add_generic_virtual_invocation:
1625 * @vtable_slot: pointer to the vtable slot
1626 * @method: the inflated generic virtual method
1627 * @code: the method's code
1629 * Registers a call via unmanaged code to a generic virtual method
1630 * instantiation or variant interface method. If the number of calls reaches a threshold
1631 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1632 * virtual method thunk.
1635 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1636 gpointer *vtable_slot,
1637 MonoMethod *method, gpointer code)
1639 static gboolean inited = FALSE;
1640 static int num_added = 0;
1642 GenericVirtualCase *gvc, *list;
1643 MonoImtBuilderEntry *entries;
1647 mono_domain_lock (domain);
1648 if (!domain->generic_virtual_cases)
1649 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1651 /* Check whether the case was already added */
1652 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1655 if (gvc->method == method)
1660 /* If not found, make a new one */
1662 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1663 gvc->method = method;
1666 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1668 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1671 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1677 if (++gvc->count == THUNK_THRESHOLD) {
1678 gpointer *old_thunk = *vtable_slot;
1679 gpointer vtable_trampoline = NULL;
1680 gpointer imt_trampoline = NULL;
1682 if ((gpointer)vtable_slot < (gpointer)vtable) {
1683 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1684 int imt_slot = MONO_IMT_SIZE + displacement;
1686 /* Force the rebuild of the thunk at the next call */
1687 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1688 *vtable_slot = imt_trampoline;
1690 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1692 entries = get_generic_virtual_entries (domain, vtable_slot);
1694 sorted = imt_sort_slot_entries (entries);
1696 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1700 MonoImtBuilderEntry *next = entries->next;
1705 for (i = 0; i < sorted->len; ++i)
1706 g_free (g_ptr_array_index (sorted, i));
1707 g_ptr_array_free (sorted, TRUE);
1710 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1711 invalidate_generic_virtual_thunk (domain, old_thunk);
1714 mono_domain_unlock (domain);
1717 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1720 * mono_class_vtable:
1721 * @domain: the application domain
1722 * @class: the class to initialize
1724 * VTables are domain specific because we create domain specific code, and
1725 * they contain the domain specific static class data.
1726 * On failure, NULL is returned, and class->exception_type is set.
1729 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1731 return mono_class_vtable_full (domain, class, FALSE);
1735 * mono_class_vtable_full:
1736 * @domain: the application domain
1737 * @class: the class to initialize
1738 * @raise_on_error if an exception should be raised on failure or not
1740 * VTables are domain specific because we create domain specific code, and
1741 * they contain the domain specific static class data.
1744 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1746 MonoClassRuntimeInfo *runtime_info;
1750 if (class->exception_type) {
1752 mono_raise_exception (mono_class_get_exception_for_failure (class));
1756 /* this check can be inlined in jitted code, too */
1757 runtime_info = class->runtime_info;
1758 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1759 return runtime_info->domain_vtables [domain->domain_id];
1760 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1764 * mono_class_try_get_vtable:
1765 * @domain: the application domain
1766 * @class: the class to initialize
1768 * This function tries to get the associated vtable from @class if
1769 * it was already created.
1772 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1774 MonoClassRuntimeInfo *runtime_info;
1778 runtime_info = class->runtime_info;
1779 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1780 return runtime_info->domain_vtables [domain->domain_id];
1785 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1788 MonoClassRuntimeInfo *runtime_info, *old_info;
1789 MonoClassField *field;
1792 int imt_table_bytes = 0;
1793 guint32 vtable_size, class_size;
1796 gpointer *interface_offsets;
1798 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1799 mono_domain_lock (domain);
1800 runtime_info = class->runtime_info;
1801 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1802 mono_domain_unlock (domain);
1803 mono_loader_unlock ();
1804 return runtime_info->domain_vtables [domain->domain_id];
1806 if (!class->inited || class->exception_type) {
1807 if (!mono_class_init (class) || class->exception_type) {
1808 mono_domain_unlock (domain);
1809 mono_loader_unlock ();
1811 mono_raise_exception (mono_class_get_exception_for_failure (class));
1816 /* Array types require that their element type be valid*/
1817 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1818 MonoClass *element_class = class->element_class;
1819 if (!element_class->inited)
1820 mono_class_init (element_class);
1822 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1823 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1824 mono_class_setup_vtable (element_class);
1826 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1827 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1828 if (class->exception_type == MONO_EXCEPTION_NONE)
1829 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1830 mono_domain_unlock (domain);
1831 mono_loader_unlock ();
1833 mono_raise_exception (mono_class_get_exception_for_failure (class));
1839 * For some classes, mono_class_init () already computed class->vtable_size, and
1840 * that is all that is needed because of the vtable trampolines.
1842 if (!class->vtable_size)
1843 mono_class_setup_vtable (class);
1845 if (class->generic_class && !class->vtable)
1846 mono_class_check_vtable_constraints (class);
1848 if (class->exception_type) {
1849 mono_domain_unlock (domain);
1850 mono_loader_unlock ();
1852 mono_raise_exception (mono_class_get_exception_for_failure (class));
1857 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1858 if (class->interface_offsets_count) {
1859 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1860 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1861 mono_stats.imt_number_of_tables++;
1862 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1865 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1866 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1869 mono_stats.used_class_count++;
1870 mono_stats.class_vtable_size += vtable_size;
1871 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1874 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1876 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1878 vt->rank = class->rank;
1879 vt->domain = domain;
1881 mono_class_compute_gc_descriptor (class);
1883 * We can't use typed allocation in the non-root domains, since the
1884 * collector needs the GC descriptor stored in the vtable even after
1885 * the mempool containing the vtable is destroyed when the domain is
1886 * unloaded. An alternative might be to allocate vtables in the GC
1887 * heap, but this does not seem to work (it leads to crashes inside
1888 * libgc). If that approach is tried, two gc descriptors need to be
1889 * allocated for each class: one for the root domain, and one for all
1890 * other domains. The second descriptor should contain a bit for the
1891 * vtable field in MonoObject, since we can no longer assume the
1892 * vtable is reachable by other roots after the appdomain is unloaded.
1894 #ifdef HAVE_BOEHM_GC
1895 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1896 vt->gc_descr = GC_NO_DESCRIPTOR;
1899 vt->gc_descr = class->gc_descr;
1901 if ((class_size = mono_class_data_size (class))) {
1902 if (class->has_static_refs) {
1903 gpointer statics_gc_descr;
1905 gsize default_bitmap [4] = {0};
1908 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1909 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1910 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1911 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1912 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1913 if (bitmap != default_bitmap)
1916 vt->data = mono_domain_alloc0 (domain, class_size);
1918 mono_stats.class_static_data_size += class_size;
1923 while ((field = mono_class_get_fields (class, &iter))) {
1924 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1926 if (mono_field_is_deleted (field))
1928 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1929 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1930 if (special_static != SPECIAL_STATIC_NONE) {
1931 guint32 size, offset;
1933 gsize default_bitmap [4] = {0};
1937 if (mono_type_is_reference (field->type)) {
1938 default_bitmap [0] = 1;
1940 bitmap = default_bitmap;
1941 } else if (mono_type_is_struct (field->type)) {
1942 fclass = mono_class_from_mono_type (field->type);
1943 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1945 default_bitmap [0] = 0;
1947 bitmap = default_bitmap;
1949 size = mono_type_size (field->type, &align);
1950 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1951 if (!domain->special_static_fields)
1952 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1953 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1954 if (bitmap != default_bitmap)
1957 * This marks the field as special static to speed up the
1958 * checks in mono_field_static_get/set_value ().
1964 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1965 MonoClass *fklass = mono_class_from_mono_type (field->type);
1966 const char *data = mono_field_get_data (field);
1968 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1969 t = (char*)vt->data + field->offset;
1970 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1973 if (fklass->valuetype) {
1974 memcpy (t, data, mono_class_value_size (fklass, NULL));
1976 /* it's a pointer type: add check */
1977 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1984 vt->max_interface_id = class->max_interface_id;
1985 vt->interface_bitmap = class->interface_bitmap;
1987 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1988 // class->name, class->interface_offsets_count);
1990 if (! ARCH_USE_IMT) {
1991 /* initialize interface offsets */
1992 for (i = 0; i < class->interface_offsets_count; ++i) {
1993 int interface_id = class->interfaces_packed [i]->interface_id;
1994 int slot = class->interface_offsets_packed [i];
1995 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1999 /* class_vtable_array keeps an array of created vtables
2001 g_ptr_array_add (domain->class_vtable_array, vt);
2002 /* class->runtime_info is protected by the loader lock, both when
2003 * it it enlarged and when it is stored info.
2006 old_info = class->runtime_info;
2007 if (old_info && old_info->max_domain >= domain->domain_id) {
2008 /* someone already created a large enough runtime info */
2009 mono_memory_barrier ();
2010 old_info->domain_vtables [domain->domain_id] = vt;
2012 int new_size = domain->domain_id;
2014 new_size = MAX (new_size, old_info->max_domain);
2016 /* make the new size a power of two */
2018 while (new_size > i)
2021 /* this is a bounded memory retention issue: may want to
2022 * handle it differently when we'll have a rcu-like system.
2024 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2025 runtime_info->max_domain = new_size - 1;
2026 /* copy the stuff from the older info */
2028 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2030 runtime_info->domain_vtables [domain->domain_id] = vt;
2032 mono_memory_barrier ();
2033 class->runtime_info = runtime_info;
2036 /* Initialize vtable */
2037 if (callbacks.get_vtable_trampoline) {
2038 // This also covers the AOT case
2039 for (i = 0; i < class->vtable_size; ++i) {
2040 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2043 mono_class_setup_vtable (class);
2045 for (i = 0; i < class->vtable_size; ++i) {
2048 if ((cm = class->vtable [i]))
2049 vt->vtable [i] = arch_create_jit_trampoline (cm);
2053 if (ARCH_USE_IMT && imt_table_bytes) {
2054 /* Now that the vtable is full, we can actually fill up the IMT */
2055 if (callbacks.get_imt_trampoline) {
2056 /* lazy construction of the IMT entries enabled */
2057 for (i = 0; i < MONO_IMT_SIZE; ++i)
2058 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2060 build_imt (class, vt, domain, interface_offsets, NULL);
2064 mono_domain_unlock (domain);
2065 mono_loader_unlock ();
2067 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2068 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2069 mono_raise_exception (mono_class_get_exception_for_failure (class));
2071 /* make sure the parent is initialized */
2072 /*FIXME shouldn't this fail the current type?*/
2074 mono_class_vtable_full (domain, class->parent, raise_on_error);
2076 /*FIXME check for OOM*/
2077 vt->type = mono_type_get_object (domain, &class->byval_arg);
2079 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2080 static void *type_desc = NULL;
2084 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2087 /* This is unregistered in
2088 unregister_vtable_reflection_type() in
2090 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2093 if (class->contextbound)
2102 * mono_class_proxy_vtable:
2103 * @domain: the application domain
2104 * @remove_class: the remote class
2106 * Creates a vtable for transparent proxies. It is basically
2107 * a copy of the real vtable of the class wrapped in @remote_class,
2108 * but all function pointers invoke the remoting functions, and
2109 * vtable->klass points to the transparent proxy class, and not to @class.
2112 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2115 MonoVTable *vt, *pvt;
2116 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2118 GSList *extra_interfaces = NULL;
2119 MonoClass *class = remote_class->proxy_class;
2120 gpointer *interface_offsets;
2124 #ifdef COMPRESSED_INTERFACE_BITMAP
2128 vt = mono_class_vtable (domain, class);
2129 g_assert (vt); /*FIXME property handle failure*/
2130 max_interface_id = vt->max_interface_id;
2132 /* Calculate vtable space for extra interfaces */
2133 for (j = 0; j < remote_class->interface_count; j++) {
2134 MonoClass* iclass = remote_class->interfaces[j];
2138 /*FIXME test for interfaces with variant generic arguments*/
2139 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2140 continue; /* interface implemented by the class */
2141 if (g_slist_find (extra_interfaces, iclass))
2144 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2146 method_count = mono_class_num_methods (iclass);
2148 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2149 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2151 for (i = 0; i < ifaces->len; ++i) {
2152 MonoClass *ic = g_ptr_array_index (ifaces, i);
2153 /*FIXME test for interfaces with variant generic arguments*/
2154 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2155 continue; /* interface implemented by the class */
2156 if (g_slist_find (extra_interfaces, ic))
2158 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2159 method_count += mono_class_num_methods (ic);
2161 g_ptr_array_free (ifaces, TRUE);
2164 extra_interface_vtsize += method_count * sizeof (gpointer);
2165 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2169 mono_stats.imt_number_of_tables++;
2170 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2171 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2172 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2174 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2175 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2178 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2180 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2182 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2184 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2185 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2187 pvt->klass = mono_defaults.transparent_proxy_class;
2188 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2189 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2191 /* initialize vtable */
2192 mono_class_setup_vtable (class);
2193 for (i = 0; i < class->vtable_size; ++i) {
2196 if ((cm = class->vtable [i]))
2197 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2199 pvt->vtable [i] = NULL;
2202 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2203 /* create trampolines for abstract methods */
2204 for (k = class; k; k = k->parent) {
2206 gpointer iter = NULL;
2207 while ((m = mono_class_get_methods (k, &iter)))
2208 if (!pvt->vtable [m->slot])
2209 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2213 pvt->max_interface_id = max_interface_id;
2214 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2215 #ifdef COMPRESSED_INTERFACE_BITMAP
2216 bitmap = g_malloc0 (bsize);
2218 bitmap = mono_domain_alloc0 (domain, bsize);
2221 if (! ARCH_USE_IMT) {
2222 /* initialize interface offsets */
2223 for (i = 0; i < class->interface_offsets_count; ++i) {
2224 int interface_id = class->interfaces_packed [i]->interface_id;
2225 int slot = class->interface_offsets_packed [i];
2226 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2229 for (i = 0; i < class->interface_offsets_count; ++i) {
2230 int interface_id = class->interfaces_packed [i]->interface_id;
2231 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2234 if (extra_interfaces) {
2235 int slot = class->vtable_size;
2241 /* Create trampolines for the methods of the interfaces */
2242 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2243 interf = list_item->data;
2245 if (! ARCH_USE_IMT) {
2246 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2248 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2252 while ((cm = mono_class_get_methods (interf, &iter)))
2253 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2255 slot += mono_class_num_methods (interf);
2257 if (! ARCH_USE_IMT) {
2258 g_slist_free (extra_interfaces);
2263 /* Now that the vtable is full, we can actually fill up the IMT */
2264 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2265 if (extra_interfaces) {
2266 g_slist_free (extra_interfaces);
2270 #ifdef COMPRESSED_INTERFACE_BITMAP
2271 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2272 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2273 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2276 pvt->interface_bitmap = bitmap;
2282 * mono_class_field_is_special_static:
2284 * Returns whether @field is a thread/context static field.
2287 mono_class_field_is_special_static (MonoClassField *field)
2289 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2291 if (mono_field_is_deleted (field))
2293 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2294 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2301 * mono_class_has_special_static_fields:
2303 * Returns whenever @klass has any thread/context static fields.
2306 mono_class_has_special_static_fields (MonoClass *klass)
2308 MonoClassField *field;
2312 while ((field = mono_class_get_fields (klass, &iter))) {
2313 g_assert (field->parent == klass);
2314 if (mono_class_field_is_special_static (field))
2322 * create_remote_class_key:
2323 * Creates an array of pointers that can be used as a hash key for a remote class.
2324 * The first element of the array is the number of pointers.
2327 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2332 if (remote_class == NULL) {
2333 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2334 key = g_malloc (sizeof(gpointer) * 3);
2335 key [0] = GINT_TO_POINTER (2);
2336 key [1] = mono_defaults.marshalbyrefobject_class;
2337 key [2] = extra_class;
2339 key = g_malloc (sizeof(gpointer) * 2);
2340 key [0] = GINT_TO_POINTER (1);
2341 key [1] = extra_class;
2344 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2345 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2346 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2347 key [1] = remote_class->proxy_class;
2349 // Keep the list of interfaces sorted
2350 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2351 if (extra_class && remote_class->interfaces [i] > extra_class) {
2352 key [j++] = extra_class;
2355 key [j] = remote_class->interfaces [i];
2358 key [j] = extra_class;
2360 // Replace the old class. The interface list is the same
2361 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2362 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2363 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2364 for (i = 0; i < remote_class->interface_count; i++)
2365 key [2 + i] = remote_class->interfaces [i];
2373 * copy_remote_class_key:
2375 * Make a copy of KEY in the domain and return the copy.
2378 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2380 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2381 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2383 memcpy (mp_key, key, key_size);
2389 * mono_remote_class:
2390 * @domain: the application domain
2391 * @class_name: name of the remote class
2393 * Creates and initializes a MonoRemoteClass object for a remote type.
2395 * Can raise an exception on failure.
2398 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2401 MonoRemoteClass *rc;
2402 gpointer* key, *mp_key;
2405 key = create_remote_class_key (NULL, proxy_class);
2407 mono_domain_lock (domain);
2408 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2412 mono_domain_unlock (domain);
2416 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2417 if (!mono_error_ok (&error)) {
2419 mono_domain_unlock (domain);
2420 mono_error_raise_exception (&error);
2423 mp_key = copy_remote_class_key (domain, key);
2427 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2428 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2429 rc->interface_count = 1;
2430 rc->interfaces [0] = proxy_class;
2431 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2433 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2434 rc->interface_count = 0;
2435 rc->proxy_class = proxy_class;
2438 rc->default_vtable = NULL;
2439 rc->xdomain_vtable = NULL;
2440 rc->proxy_class_name = name;
2441 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2443 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2445 mono_domain_unlock (domain);
2450 * clone_remote_class:
2451 * Creates a copy of the remote_class, adding the provided class or interface
2453 static MonoRemoteClass*
2454 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2456 MonoRemoteClass *rc;
2457 gpointer* key, *mp_key;
2459 key = create_remote_class_key (remote_class, extra_class);
2460 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2466 mp_key = copy_remote_class_key (domain, key);
2470 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2472 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2473 rc->proxy_class = remote_class->proxy_class;
2474 rc->interface_count = remote_class->interface_count + 1;
2476 // Keep the list of interfaces sorted, since the hash key of
2477 // the remote class depends on this
2478 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2479 if (remote_class->interfaces [i] > extra_class && i == j)
2480 rc->interfaces [j++] = extra_class;
2481 rc->interfaces [j] = remote_class->interfaces [i];
2484 rc->interfaces [j] = extra_class;
2486 // Replace the old class. The interface array is the same
2487 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2488 rc->proxy_class = extra_class;
2489 rc->interface_count = remote_class->interface_count;
2490 if (rc->interface_count > 0)
2491 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2494 rc->default_vtable = NULL;
2495 rc->xdomain_vtable = NULL;
2496 rc->proxy_class_name = remote_class->proxy_class_name;
2498 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2504 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2506 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2507 mono_domain_lock (domain);
2508 if (rp->target_domain_id != -1) {
2509 if (remote_class->xdomain_vtable == NULL)
2510 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2511 mono_domain_unlock (domain);
2512 mono_loader_unlock ();
2513 return remote_class->xdomain_vtable;
2515 if (remote_class->default_vtable == NULL) {
2518 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2519 klass = mono_class_from_mono_type (type);
2520 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2521 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2523 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2526 mono_domain_unlock (domain);
2527 mono_loader_unlock ();
2528 return remote_class->default_vtable;
2532 * mono_upgrade_remote_class:
2533 * @domain: the application domain
2534 * @tproxy: the proxy whose remote class has to be upgraded.
2535 * @klass: class to which the remote class can be casted.
2537 * Updates the vtable of the remote class by adding the necessary method slots
2538 * and interface offsets so it can be safely casted to klass. klass can be a
2539 * class or an interface.
2542 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2544 MonoTransparentProxy *tproxy;
2545 MonoRemoteClass *remote_class;
2546 gboolean redo_vtable;
2548 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2549 mono_domain_lock (domain);
2551 tproxy = (MonoTransparentProxy*) proxy_object;
2552 remote_class = tproxy->remote_class;
2554 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2557 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2558 if (remote_class->interfaces [i] == klass)
2559 redo_vtable = FALSE;
2562 redo_vtable = (remote_class->proxy_class != klass);
2566 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2567 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2570 mono_domain_unlock (domain);
2571 mono_loader_unlock ();
2576 * mono_object_get_virtual_method:
2577 * @obj: object to operate on.
2580 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2581 * the instance of a callvirt of method.
2584 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2587 MonoMethod **vtable;
2589 MonoMethod *res = NULL;
2591 klass = mono_object_class (obj);
2592 if (klass == mono_defaults.transparent_proxy_class) {
2593 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2599 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2602 mono_class_setup_vtable (klass);
2603 vtable = klass->vtable;
2605 if (method->slot == -1) {
2606 /* method->slot might not be set for instances of generic methods */
2607 if (method->is_inflated) {
2608 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2609 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2612 g_assert_not_reached ();
2616 /* check method->slot is a valid index: perform isinstance? */
2617 if (method->slot != -1) {
2618 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2620 gboolean variance_used = FALSE;
2621 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2622 g_assert (iface_offset > 0);
2623 res = vtable [iface_offset + method->slot];
2626 res = vtable [method->slot];
2631 /* It may be an interface, abstract class method or generic method */
2632 if (!res || mono_method_signature (res)->generic_param_count)
2635 /* generic methods demand invoke_with_check */
2636 if (mono_method_signature (res)->generic_param_count)
2637 res = mono_marshal_get_remoting_invoke_with_check (res);
2640 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2641 res = mono_cominterop_get_invoke (res);
2644 res = mono_marshal_get_remoting_invoke (res);
2647 if (method->is_inflated) {
2648 /* Have to inflate the result */
2649 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2659 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2661 g_error ("runtime invoke called on uninitialized runtime");
2665 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2668 * mono_runtime_invoke:
2669 * @method: method to invoke
2670 * @obJ: object instance
2671 * @params: arguments to the method
2672 * @exc: exception information.
2674 * Invokes the method represented by @method on the object @obj.
2676 * obj is the 'this' pointer, it should be NULL for static
2677 * methods, a MonoObject* for object instances and a pointer to
2678 * the value type for value types.
2680 * The params array contains the arguments to the method with the
2681 * same convention: MonoObject* pointers for object instances and
2682 * pointers to the value type otherwise.
2684 * From unmanaged code you'll usually use the
2685 * mono_runtime_invoke() variant.
2687 * Note that this function doesn't handle virtual methods for
2688 * you, it will exec the exact method you pass: we still need to
2689 * expose a function to lookup the derived class implementation
2690 * of a virtual method (there are examples of this in the code,
2693 * You can pass NULL as the exc argument if you don't want to
2694 * catch exceptions, otherwise, *exc will be set to the exception
2695 * thrown, if any. if an exception is thrown, you can't use the
2696 * MonoObject* result from the function.
2698 * If the method returns a value type, it is boxed in an object
2702 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2706 if (mono_runtime_get_no_exec ())
2707 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2709 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2710 mono_profiler_method_start_invoke (method);
2712 result = default_mono_runtime_invoke (method, obj, params, exc);
2714 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2715 mono_profiler_method_end_invoke (method);
2721 * mono_method_get_unmanaged_thunk:
2722 * @method: method to generate a thunk for.
2724 * Returns an unmanaged->managed thunk that can be used to call
2725 * a managed method directly from C.
2727 * The thunk's C signature closely matches the managed signature:
2729 * C#: public bool Equals (object obj);
2730 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2731 * MonoObject*, MonoException**);
2733 * The 1st ("this") parameter must not be used with static methods:
2735 * C#: public static bool ReferenceEquals (object a, object b);
2736 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2739 * The last argument must be a non-null pointer of a MonoException* pointer.
2740 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2741 * exception has been thrown in managed code. Otherwise it will point
2742 * to the MonoException* caught by the thunk. In this case, the result of
2743 * the thunk is undefined:
2745 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2746 * MonoException *ex = NULL;
2747 * Equals func = mono_method_get_unmanaged_thunk (method);
2748 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2750 * // handle exception
2753 * The calling convention of the thunk matches the platform's default
2754 * convention. This means that under Windows, C declarations must
2755 * contain the __stdcall attribute:
2757 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2758 * MonoObject*, MonoException**);
2762 * Value type arguments and return values are treated as they were objects:
2764 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2765 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2767 * Arguments must be properly boxed upon trunk's invocation, while return
2768 * values must be unboxed.
2771 mono_method_get_unmanaged_thunk (MonoMethod *method)
2773 method = mono_marshal_get_thunk_invoke_wrapper (method);
2774 return mono_compile_method (method);
2778 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2782 /* object fields cannot be byref, so we don't need a
2784 gpointer *p = (gpointer*)dest;
2791 case MONO_TYPE_BOOLEAN:
2793 case MONO_TYPE_U1: {
2794 guint8 *p = (guint8*)dest;
2795 *p = value ? *(guint8*)value : 0;
2800 case MONO_TYPE_CHAR: {
2801 guint16 *p = (guint16*)dest;
2802 *p = value ? *(guint16*)value : 0;
2805 #if SIZEOF_VOID_P == 4
2810 case MONO_TYPE_U4: {
2811 gint32 *p = (gint32*)dest;
2812 *p = value ? *(gint32*)value : 0;
2815 #if SIZEOF_VOID_P == 8
2820 case MONO_TYPE_U8: {
2821 gint64 *p = (gint64*)dest;
2822 *p = value ? *(gint64*)value : 0;
2825 case MONO_TYPE_R4: {
2826 float *p = (float*)dest;
2827 *p = value ? *(float*)value : 0;
2830 case MONO_TYPE_R8: {
2831 double *p = (double*)dest;
2832 *p = value ? *(double*)value : 0;
2835 case MONO_TYPE_STRING:
2836 case MONO_TYPE_SZARRAY:
2837 case MONO_TYPE_CLASS:
2838 case MONO_TYPE_OBJECT:
2839 case MONO_TYPE_ARRAY:
2840 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2842 case MONO_TYPE_FNPTR:
2843 case MONO_TYPE_PTR: {
2844 gpointer *p = (gpointer*)dest;
2845 *p = deref_pointer? *(gpointer*)value: value;
2848 case MONO_TYPE_VALUETYPE:
2849 /* note that 't' and 'type->type' can be different */
2850 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2851 t = mono_class_enum_basetype (type->data.klass)->type;
2854 MonoClass *class = mono_class_from_mono_type (type);
2855 int size = mono_class_value_size (class, NULL);
2857 memset (dest, 0, size);
2859 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2862 case MONO_TYPE_GENERICINST:
2863 t = type->data.generic_class->container_class->byval_arg.type;
2866 g_warning ("got type %x", type->type);
2867 g_assert_not_reached ();
2872 * mono_field_set_value:
2873 * @obj: Instance object
2874 * @field: MonoClassField describing the field to set
2875 * @value: The value to be set
2877 * Sets the value of the field described by @field in the object instance @obj
2878 * to the value passed in @value. This method should only be used for instance
2879 * fields. For static fields, use mono_field_static_set_value.
2881 * The value must be on the native format of the field type.
2884 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2888 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2890 dest = (char*)obj + field->offset;
2891 set_value (field->type, dest, value, FALSE);
2895 * mono_field_static_set_value:
2896 * @field: MonoClassField describing the field to set
2897 * @value: The value to be set
2899 * Sets the value of the static field described by @field
2900 * to the value passed in @value.
2902 * The value must be on the native format of the field type.
2905 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2909 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2910 /* you cant set a constant! */
2911 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2913 if (field->offset == -1) {
2914 /* Special static */
2915 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2916 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2918 dest = (char*)vt->data + field->offset;
2920 set_value (field->type, dest, value, FALSE);
2923 /* Used by the debugger */
2925 mono_vtable_get_static_field_data (MonoVTable *vt)
2931 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2935 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2936 if (field->offset == -1) {
2937 /* Special static */
2938 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2939 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2941 src = (guint8*)vt->data + field->offset;
2944 src = (guint8*)obj + field->offset;
2951 * mono_field_get_value:
2952 * @obj: Object instance
2953 * @field: MonoClassField describing the field to fetch information from
2954 * @value: pointer to the location where the value will be stored
2956 * Use this routine to get the value of the field @field in the object
2959 * The pointer provided by value must be of the field type, for reference
2960 * types this is a MonoObject*, for value types its the actual pointer to
2965 * mono_field_get_value (obj, int_field, &i);
2968 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2974 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2976 src = (char*)obj + field->offset;
2977 set_value (field->type, value, src, TRUE);
2981 * mono_field_get_value_object:
2982 * @domain: domain where the object will be created (if boxing)
2983 * @field: MonoClassField describing the field to fetch information from
2984 * @obj: The object instance for the field.
2986 * Returns: a new MonoObject with the value from the given field. If the
2987 * field represents a value type, the value is boxed.
2991 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2995 MonoVTable *vtable = NULL;
2997 gboolean is_static = FALSE;
2998 gboolean is_ref = FALSE;
2999 gboolean is_literal = FALSE;
3000 gboolean is_ptr = FALSE;
3002 MonoType *type = mono_field_get_type_checked (field, &error);
3004 if (!mono_error_ok (&error))
3005 mono_error_raise_exception (&error);
3007 switch (type->type) {
3008 case MONO_TYPE_STRING:
3009 case MONO_TYPE_OBJECT:
3010 case MONO_TYPE_CLASS:
3011 case MONO_TYPE_ARRAY:
3012 case MONO_TYPE_SZARRAY:
3017 case MONO_TYPE_BOOLEAN:
3020 case MONO_TYPE_CHAR:
3029 case MONO_TYPE_VALUETYPE:
3030 is_ref = type->byref;
3032 case MONO_TYPE_GENERICINST:
3033 is_ref = !mono_type_generic_inst_is_valuetype (type);
3039 g_error ("type 0x%x not handled in "
3040 "mono_field_get_value_object", type->type);
3044 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3047 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3051 vtable = mono_class_vtable (domain, field->parent);
3053 char *name = mono_type_get_full_name (field->parent);
3054 /*FIXME extend this to use the MonoError api*/
3055 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3059 if (!vtable->initialized)
3060 mono_runtime_class_init (vtable);
3068 get_default_field_value (domain, field, &o);
3069 } else if (is_static) {
3070 mono_field_static_get_value (vtable, field, &o);
3072 mono_field_get_value (obj, field, &o);
3078 static MonoMethod *m;
3084 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3085 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3091 get_default_field_value (domain, field, v);
3092 } else if (is_static) {
3093 mono_field_static_get_value (vtable, field, v);
3095 mono_field_get_value (obj, field, v);
3098 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3100 args [1] = mono_type_get_object (mono_domain_get (), type);
3102 return mono_runtime_invoke (m, NULL, args, NULL);
3105 /* boxed value type */
3106 klass = mono_class_from_mono_type (type);
3108 if (mono_class_is_nullable (klass))
3109 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3111 o = mono_object_new (domain, klass);
3112 v = ((gchar *) o) + sizeof (MonoObject);
3115 get_default_field_value (domain, field, v);
3116 } else if (is_static) {
3117 mono_field_static_get_value (vtable, field, v);
3119 mono_field_get_value (obj, field, v);
3126 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3129 const char *p = blob;
3130 mono_metadata_decode_blob_size (p, &p);
3133 case MONO_TYPE_BOOLEAN:
3136 *(guint8 *) value = *p;
3138 case MONO_TYPE_CHAR:
3141 *(guint16*) value = read16 (p);
3145 *(guint32*) value = read32 (p);
3149 *(guint64*) value = read64 (p);
3152 readr4 (p, (float*) value);
3155 readr8 (p, (double*) value);
3157 case MONO_TYPE_STRING:
3158 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3160 case MONO_TYPE_CLASS:
3161 *(gpointer*) value = NULL;
3165 g_warning ("type 0x%02x should not be in constant table", type);
3171 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3173 MonoTypeEnum def_type;
3176 data = mono_class_get_field_default_value (field, &def_type);
3177 mono_get_constant_value_from_blob (domain, def_type, data, value);
3181 * mono_field_static_get_value:
3182 * @vt: vtable to the object
3183 * @field: MonoClassField describing the field to fetch information from
3184 * @value: where the value is returned
3186 * Use this routine to get the value of the static field @field value.
3188 * The pointer provided by value must be of the field type, for reference
3189 * types this is a MonoObject*, for value types its the actual pointer to
3194 * mono_field_static_get_value (vt, int_field, &i);
3197 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3201 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3203 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3204 get_default_field_value (vt->domain, field, value);
3208 if (field->offset == -1) {
3209 /* Special static */
3210 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3211 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3213 src = (char*)vt->data + field->offset;
3215 set_value (field->type, value, src, TRUE);
3219 * mono_property_set_value:
3220 * @prop: MonoProperty to set
3221 * @obj: instance object on which to act
3222 * @params: parameters to pass to the propery
3223 * @exc: optional exception
3225 * Invokes the property's set method with the given arguments on the
3226 * object instance obj (or NULL for static properties).
3228 * You can pass NULL as the exc argument if you don't want to
3229 * catch exceptions, otherwise, *exc will be set to the exception
3230 * thrown, if any. if an exception is thrown, you can't use the
3231 * MonoObject* result from the function.
3234 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3236 default_mono_runtime_invoke (prop->set, obj, params, exc);
3240 * mono_property_get_value:
3241 * @prop: MonoProperty to fetch
3242 * @obj: instance object on which to act
3243 * @params: parameters to pass to the propery
3244 * @exc: optional exception
3246 * Invokes the property's get method with the given arguments on the
3247 * object instance obj (or NULL for static properties).
3249 * You can pass NULL as the exc argument if you don't want to
3250 * catch exceptions, otherwise, *exc will be set to the exception
3251 * thrown, if any. if an exception is thrown, you can't use the
3252 * MonoObject* result from the function.
3254 * Returns: the value from invoking the get method on the property.
3257 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3259 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3263 * mono_nullable_init:
3264 * @buf: The nullable structure to initialize.
3265 * @value: the value to initialize from
3266 * @klass: the type for the object
3268 * Initialize the nullable structure pointed to by @buf from @value which
3269 * should be a boxed value type. The size of @buf should be able to hold
3270 * as much data as the @klass->instance_size (which is the number of bytes
3271 * that will be copies).
3273 * Since Nullables have variable structure, we can not define a C
3274 * structure for them.
3277 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3279 MonoClass *param_class = klass->cast_class;
3281 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3282 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3284 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3286 if (param_class->has_references)
3287 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3289 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3291 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3296 * mono_nullable_box:
3297 * @buf: The buffer representing the data to be boxed
3298 * @klass: the type to box it as.
3300 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3304 mono_nullable_box (guint8 *buf, MonoClass *klass)
3306 MonoClass *param_class = klass->cast_class;
3308 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3309 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3311 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3312 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3313 if (param_class->has_references)
3314 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3316 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3324 * mono_get_delegate_invoke:
3325 * @klass: The delegate class
3327 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3330 mono_get_delegate_invoke (MonoClass *klass)
3334 /* This is called at runtime, so avoid the slower search in metadata */
3335 mono_class_setup_methods (klass);
3336 if (klass->exception_type)
3338 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3343 * mono_runtime_delegate_invoke:
3344 * @delegate: pointer to a delegate object.
3345 * @params: parameters for the delegate.
3346 * @exc: Pointer to the exception result.
3348 * Invokes the delegate method @delegate with the parameters provided.
3350 * You can pass NULL as the exc argument if you don't want to
3351 * catch exceptions, otherwise, *exc will be set to the exception
3352 * thrown, if any. if an exception is thrown, you can't use the
3353 * MonoObject* result from the function.
3356 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3360 im = mono_get_delegate_invoke (delegate->vtable->klass);
3363 return mono_runtime_invoke (im, delegate, params, exc);
3366 static char **main_args = NULL;
3367 static int num_main_args;
3370 * mono_runtime_get_main_args:
3372 * Returns: a MonoArray with the arguments passed to the main program
3375 mono_runtime_get_main_args (void)
3379 MonoDomain *domain = mono_domain_get ();
3384 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3386 for (i = 0; i < num_main_args; ++i)
3387 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3393 free_main_args (void)
3397 for (i = 0; i < num_main_args; ++i)
3398 g_free (main_args [i]);
3403 * mono_runtime_run_main:
3404 * @method: the method to start the application with (usually Main)
3405 * @argc: number of arguments from the command line
3406 * @argv: array of strings from the command line
3407 * @exc: excetption results
3409 * Execute a standard Main() method (argc/argv contains the
3410 * executable name). This method also sets the command line argument value
3411 * needed by System.Environment.
3416 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3420 MonoArray *args = NULL;
3421 MonoDomain *domain = mono_domain_get ();
3422 gchar *utf8_fullpath;
3423 MonoMethodSignature *sig;
3425 g_assert (method != NULL);
3427 mono_thread_set_main (mono_thread_current ());
3429 main_args = g_new0 (char*, argc);
3430 num_main_args = argc;
3432 if (!g_path_is_absolute (argv [0])) {
3433 gchar *basename = g_path_get_basename (argv [0]);
3434 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3438 utf8_fullpath = mono_utf8_from_external (fullpath);
3439 if(utf8_fullpath == NULL) {
3440 /* Printing the arg text will cause glib to
3441 * whinge about "Invalid UTF-8", but at least
3442 * its relevant, and shows the problem text
3445 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3446 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3453 utf8_fullpath = mono_utf8_from_external (argv[0]);
3454 if(utf8_fullpath == NULL) {
3455 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3456 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3461 main_args [0] = utf8_fullpath;
3463 for (i = 1; i < argc; ++i) {
3466 utf8_arg=mono_utf8_from_external (argv[i]);
3467 if(utf8_arg==NULL) {
3468 /* Ditto the comment about Invalid UTF-8 here */
3469 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3470 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3474 main_args [i] = utf8_arg;
3479 sig = mono_method_signature (method);
3481 g_print ("Unable to load Main method.\n");
3485 if (sig->param_count) {
3486 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3487 for (i = 0; i < argc; ++i) {
3488 /* The encodings should all work, given that
3489 * we've checked all these args for the
3492 gchar *str = mono_utf8_from_external (argv [i]);
3493 MonoString *arg = mono_string_new (domain, str);
3494 mono_array_setref (args, i, arg);
3498 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3501 mono_assembly_set_main (method->klass->image->assembly);
3503 return mono_runtime_exec_main (method, args, exc);
3507 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3509 static MonoMethod *serialize_method;
3514 if (!serialize_method) {
3515 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3516 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3519 if (!serialize_method) {
3524 g_assert (!mono_object_class (obj)->marshalbyref);
3528 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3536 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3538 static MonoMethod *deserialize_method;
3543 if (!deserialize_method) {
3544 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3545 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3547 if (!deserialize_method) {
3554 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3562 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3564 static MonoMethod *get_proxy_method;
3566 MonoDomain *domain = mono_domain_get ();
3567 MonoRealProxy *real_proxy;
3568 MonoReflectionType *reflection_type;
3569 MonoTransparentProxy *transparent_proxy;
3571 if (!get_proxy_method)
3572 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3574 g_assert (obj->vtable->klass->marshalbyref);
3576 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3577 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3579 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3580 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3583 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3587 return (MonoObject*) transparent_proxy;
3591 * mono_object_xdomain_representation
3593 * @target_domain: a domain
3594 * @exc: pointer to a MonoObject*
3596 * Creates a representation of obj in the domain target_domain. This
3597 * is either a copy of obj arrived through via serialization and
3598 * deserialization or a proxy, depending on whether the object is
3599 * serializable or marshal by ref. obj must not be in target_domain.
3601 * If the object cannot be represented in target_domain, NULL is
3602 * returned and *exc is set to an appropriate exception.
3605 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3607 MonoObject *deserialized = NULL;
3608 gboolean failure = FALSE;
3612 if (mono_object_class (obj)->marshalbyref) {
3613 deserialized = make_transparent_proxy (obj, &failure, exc);
3615 MonoDomain *domain = mono_domain_get ();
3616 MonoObject *serialized;
3618 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3619 serialized = serialize_object (obj, &failure, exc);
3620 mono_domain_set_internal_with_options (target_domain, FALSE);
3622 deserialized = deserialize_object (serialized, &failure, exc);
3623 if (domain != target_domain)
3624 mono_domain_set_internal_with_options (domain, FALSE);
3627 return deserialized;
3630 /* Used in call_unhandled_exception_delegate */
3632 create_unhandled_exception_eventargs (MonoObject *exc)
3636 MonoMethod *method = NULL;
3637 MonoBoolean is_terminating = TRUE;
3640 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3643 mono_class_init (klass);
3645 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3646 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3650 args [1] = &is_terminating;
3652 obj = mono_object_new (mono_domain_get (), klass);
3653 mono_runtime_invoke (method, obj, args, NULL);
3658 /* Used in mono_unhandled_exception */
3660 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3661 MonoObject *e = NULL;
3663 MonoDomain *current_domain = mono_domain_get ();
3665 if (domain != current_domain)
3666 mono_domain_set_internal_with_options (domain, FALSE);
3668 g_assert (domain == mono_object_domain (domain->domain));
3670 if (mono_object_domain (exc) != domain) {
3671 MonoObject *serialization_exc;
3673 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3675 if (serialization_exc) {
3677 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3680 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3681 "System.Runtime.Serialization", "SerializationException",
3682 "Could not serialize unhandled exception.");
3686 g_assert (mono_object_domain (exc) == domain);
3688 pa [0] = domain->domain;
3689 pa [1] = create_unhandled_exception_eventargs (exc);
3690 mono_runtime_delegate_invoke (delegate, pa, &e);
3692 if (domain != current_domain)
3693 mono_domain_set_internal_with_options (current_domain, FALSE);
3697 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3698 if (!mono_error_ok (&error)) {
3699 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3700 mono_error_cleanup (&error);
3702 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3708 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3711 * mono_runtime_unhandled_exception_policy_set:
3712 * @policy: the new policy
3714 * This is a VM internal routine.
3716 * Sets the runtime policy for handling unhandled exceptions.
3719 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3720 runtime_unhandled_exception_policy = policy;
3724 * mono_runtime_unhandled_exception_policy_get:
3726 * This is a VM internal routine.
3728 * Gets the runtime policy for handling unhandled exceptions.
3730 MonoRuntimeUnhandledExceptionPolicy
3731 mono_runtime_unhandled_exception_policy_get (void) {
3732 return runtime_unhandled_exception_policy;
3736 * mono_unhandled_exception:
3737 * @exc: exception thrown
3739 * This is a VM internal routine.
3741 * We call this function when we detect an unhandled exception
3742 * in the default domain.
3744 * It invokes the * UnhandledException event in AppDomain or prints
3745 * a warning to the console
3748 mono_unhandled_exception (MonoObject *exc)
3750 MonoDomain *current_domain = mono_domain_get ();
3751 MonoDomain *root_domain = mono_get_root_domain ();
3752 MonoClassField *field;
3753 MonoObject *current_appdomain_delegate;
3754 MonoObject *root_appdomain_delegate;
3756 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3757 "UnhandledException");
3760 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3761 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3762 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3763 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3764 if (current_domain != root_domain) {
3765 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3767 current_appdomain_delegate = NULL;
3770 /* set exitcode only if we will abort the process */
3772 mono_environment_exitcode_set (1);
3773 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3774 mono_print_unhandled_exception (exc);
3776 if (root_appdomain_delegate) {
3777 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3779 if (current_appdomain_delegate) {
3780 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3787 * mono_runtime_exec_managed_code:
3788 * @domain: Application domain
3789 * @main_func: function to invoke from the execution thread
3790 * @main_args: parameter to the main_func
3792 * Launch a new thread to execute a function
3794 * main_func is called back from the thread with main_args as the
3795 * parameter. The callback function is expected to start Main()
3796 * eventually. This function then waits for all managed threads to
3798 * It is not necesseray anymore to execute managed code in a subthread,
3799 * so this function should not be used anymore by default: just
3800 * execute the code and then call mono_thread_manage ().
3803 mono_runtime_exec_managed_code (MonoDomain *domain,
3804 MonoMainThreadFunc main_func,
3807 mono_thread_create (domain, main_func, main_args);
3809 mono_thread_manage ();
3813 * Execute a standard Main() method (args doesn't contain the
3817 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3822 MonoCustomAttrInfo* cinfo;
3823 gboolean has_stathread_attribute;
3824 MonoInternalThread* thread = mono_thread_internal_current ();
3830 domain = mono_object_domain (args);
3831 if (!domain->entry_assembly) {
3833 MonoAssembly *assembly;
3835 assembly = method->klass->image->assembly;
3836 domain->entry_assembly = assembly;
3837 /* Domains created from another domain already have application_base and configuration_file set */
3838 if (domain->setup->application_base == NULL) {
3839 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3842 if (domain->setup->configuration_file == NULL) {
3843 str = g_strconcat (assembly->image->name, ".config", NULL);
3844 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3846 mono_set_private_bin_path_from_config (domain);
3850 cinfo = mono_custom_attrs_from_method (method);
3852 static MonoClass *stathread_attribute = NULL;
3853 if (!stathread_attribute)
3854 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3855 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3857 mono_custom_attrs_free (cinfo);
3859 has_stathread_attribute = FALSE;
3861 if (has_stathread_attribute) {
3862 thread->apartment_state = ThreadApartmentState_STA;
3864 thread->apartment_state = ThreadApartmentState_MTA;
3866 mono_thread_init_apartment_state ();
3868 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3870 /* FIXME: check signature of method */
3871 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3873 res = mono_runtime_invoke (method, NULL, pa, exc);
3875 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3879 mono_environment_exitcode_set (rval);
3881 mono_runtime_invoke (method, NULL, pa, exc);
3885 /* If the return type of Main is void, only
3886 * set the exitcode if an exception was thrown
3887 * (we don't want to blow away an
3888 * explicitly-set exit code)
3891 mono_environment_exitcode_set (rval);
3895 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3901 * mono_install_runtime_invoke:
3902 * @func: Function to install
3904 * This is a VM internal routine
3907 mono_install_runtime_invoke (MonoInvokeFunc func)
3909 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3914 * mono_runtime_invoke_array:
3915 * @method: method to invoke
3916 * @obJ: object instance
3917 * @params: arguments to the method
3918 * @exc: exception information.
3920 * Invokes the method represented by @method on the object @obj.
3922 * obj is the 'this' pointer, it should be NULL for static
3923 * methods, a MonoObject* for object instances and a pointer to
3924 * the value type for value types.
3926 * The params array contains the arguments to the method with the
3927 * same convention: MonoObject* pointers for object instances and
3928 * pointers to the value type otherwise. The _invoke_array
3929 * variant takes a C# object[] as the params argument (MonoArray
3930 * *params): in this case the value types are boxed inside the
3931 * respective reference representation.
3933 * From unmanaged code you'll usually use the
3934 * mono_runtime_invoke() variant.
3936 * Note that this function doesn't handle virtual methods for
3937 * you, it will exec the exact method you pass: we still need to
3938 * expose a function to lookup the derived class implementation
3939 * of a virtual method (there are examples of this in the code,
3942 * You can pass NULL as the exc argument if you don't want to
3943 * catch exceptions, otherwise, *exc will be set to the exception
3944 * thrown, if any. if an exception is thrown, you can't use the
3945 * MonoObject* result from the function.
3947 * If the method returns a value type, it is boxed in an object
3951 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3954 MonoMethodSignature *sig = mono_method_signature (method);
3955 gpointer *pa = NULL;
3958 gboolean has_byref_nullables = FALSE;
3960 if (NULL != params) {
3961 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3962 for (i = 0; i < mono_array_length (params); i++) {
3963 MonoType *t = sig->params [i];
3969 case MONO_TYPE_BOOLEAN:
3972 case MONO_TYPE_CHAR:
3981 case MONO_TYPE_VALUETYPE:
3982 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3983 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3984 pa [i] = mono_array_get (params, MonoObject*, i);
3986 has_byref_nullables = TRUE;
3988 /* MS seems to create the objects if a null is passed in */
3989 if (!mono_array_get (params, MonoObject*, i))
3990 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3994 * We can't pass the unboxed vtype byref to the callee, since
3995 * that would mean the callee would be able to modify boxed
3996 * primitive types. So we (and MS) make a copy of the boxed
3997 * object, pass that to the callee, and replace the original
3998 * boxed object in the arg array with the copy.
4000 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4001 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4002 mono_array_setref (params, i, copy);
4005 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4008 case MONO_TYPE_STRING:
4009 case MONO_TYPE_OBJECT:
4010 case MONO_TYPE_CLASS:
4011 case MONO_TYPE_ARRAY:
4012 case MONO_TYPE_SZARRAY:
4014 pa [i] = mono_array_addr (params, MonoObject*, i);
4015 // FIXME: I need to check this code path
4017 pa [i] = mono_array_get (params, MonoObject*, i);
4019 case MONO_TYPE_GENERICINST:
4021 t = &t->data.generic_class->container_class->this_arg;
4023 t = &t->data.generic_class->container_class->byval_arg;
4025 case MONO_TYPE_PTR: {
4028 /* The argument should be an IntPtr */
4029 arg = mono_array_get (params, MonoObject*, i);
4033 g_assert (arg->vtable->klass == mono_defaults.int_class);
4034 pa [i] = ((MonoIntPtr*)arg)->m_value;
4039 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4044 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4047 if (mono_class_is_nullable (method->klass)) {
4048 /* Need to create a boxed vtype instead */
4054 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4058 obj = mono_object_new (mono_domain_get (), method->klass);
4059 g_assert (obj); /*maybe we should raise a TLE instead?*/
4060 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4061 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4063 if (method->klass->valuetype)
4064 o = mono_object_unbox (obj);
4067 } else if (method->klass->valuetype) {
4068 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4071 mono_runtime_invoke (method, o, pa, exc);
4074 if (mono_class_is_nullable (method->klass)) {
4075 MonoObject *nullable;
4077 /* Convert the unboxed vtype into a Nullable structure */
4078 nullable = mono_object_new (mono_domain_get (), method->klass);
4080 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4081 obj = mono_object_unbox (nullable);
4084 /* obj must be already unboxed if needed */
4085 res = mono_runtime_invoke (method, obj, pa, exc);
4087 if (sig->ret->type == MONO_TYPE_PTR) {
4088 MonoClass *pointer_class;
4089 static MonoMethod *box_method;
4091 MonoObject *box_exc;
4094 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4095 * convert it to a Pointer object.
4097 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4099 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4101 g_assert (res->vtable->klass == mono_defaults.int_class);
4102 box_args [0] = ((MonoIntPtr*)res)->m_value;
4103 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4104 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4105 g_assert (!box_exc);
4108 if (has_byref_nullables) {
4110 * The runtime invoke wrapper already converted byref nullables back,
4111 * and stored them in pa, we just need to copy them back to the
4114 for (i = 0; i < mono_array_length (params); i++) {
4115 MonoType *t = sig->params [i];
4117 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4118 mono_array_setref (params, i, pa [i]);
4127 arith_overflow (void)
4129 mono_raise_exception (mono_get_exception_overflow ());
4133 * mono_object_allocate:
4134 * @size: number of bytes to allocate
4136 * This is a very simplistic routine until we have our GC-aware
4139 * Returns: an allocated object of size @size, or NULL on failure.
4141 static inline void *
4142 mono_object_allocate (size_t size, MonoVTable *vtable)
4145 mono_stats.new_object_count++;
4146 ALLOC_OBJECT (o, vtable, size);
4152 * mono_object_allocate_ptrfree:
4153 * @size: number of bytes to allocate
4155 * Note that the memory allocated is not zeroed.
4156 * Returns: an allocated object of size @size, or NULL on failure.
4158 static inline void *
4159 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4162 mono_stats.new_object_count++;
4163 ALLOC_PTRFREE (o, vtable, size);
4167 static inline void *
4168 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4171 ALLOC_TYPED (o, size, vtable);
4172 mono_stats.new_object_count++;
4179 * @klass: the class of the object that we want to create
4181 * Returns: a newly created object whose definition is
4182 * looked up using @klass. This will not invoke any constructors,
4183 * so the consumer of this routine has to invoke any constructors on
4184 * its own to initialize the object.
4186 * It returns NULL on failure.
4189 mono_object_new (MonoDomain *domain, MonoClass *klass)
4193 MONO_ARCH_SAVE_REGS;
4194 vtable = mono_class_vtable (domain, klass);
4197 return mono_object_new_specific (vtable);
4201 * mono_object_new_specific:
4202 * @vtable: the vtable of the object that we want to create
4204 * Returns: A newly created object with class and domain specified
4208 mono_object_new_specific (MonoVTable *vtable)
4212 MONO_ARCH_SAVE_REGS;
4214 /* check for is_com_object for COM Interop */
4215 if (vtable->remote || vtable->klass->is_com_object)
4218 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4221 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4224 mono_class_init (klass);
4226 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4228 vtable->domain->create_proxy_for_type_method = im;
4231 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4233 o = mono_runtime_invoke (im, NULL, pa, NULL);
4234 if (o != NULL) return o;
4237 return mono_object_new_alloc_specific (vtable);
4241 mono_object_new_alloc_specific (MonoVTable *vtable)
4245 if (!vtable->klass->has_references) {
4246 o = mono_object_new_ptrfree (vtable);
4247 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4248 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4250 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4251 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4253 if (G_UNLIKELY (vtable->klass->has_finalize))
4254 mono_object_register_finalizer (o);
4256 if (G_UNLIKELY (profile_allocs))
4257 mono_profiler_allocation (o, vtable->klass);
4262 mono_object_new_fast (MonoVTable *vtable)
4265 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4270 mono_object_new_ptrfree (MonoVTable *vtable)
4273 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4274 #if NEED_TO_ZERO_PTRFREE
4275 /* an inline memset is much faster for the common vcase of small objects
4276 * note we assume the allocated size is a multiple of sizeof (void*).
4278 if (vtable->klass->instance_size < 128) {
4280 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4281 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4287 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4294 mono_object_new_ptrfree_box (MonoVTable *vtable)
4297 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4298 /* the object will be boxed right away, no need to memzero it */
4303 * mono_class_get_allocation_ftn:
4305 * @for_box: the object will be used for boxing
4306 * @pass_size_in_words:
4308 * Return the allocation function appropriate for the given class.
4312 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4314 *pass_size_in_words = FALSE;
4316 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4317 profile_allocs = FALSE;
4319 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4320 return mono_object_new_specific;
4322 if (!vtable->klass->has_references) {
4323 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4325 return mono_object_new_ptrfree_box;
4326 return mono_object_new_ptrfree;
4329 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4331 return mono_object_new_fast;
4334 * FIXME: This is actually slower than mono_object_new_fast, because
4335 * of the overhead of parameter passing.
4338 *pass_size_in_words = TRUE;
4339 #ifdef GC_REDIRECT_TO_LOCAL
4340 return GC_local_gcj_fast_malloc;
4342 return GC_gcj_fast_malloc;
4347 return mono_object_new_specific;
4351 * mono_object_new_from_token:
4352 * @image: Context where the type_token is hosted
4353 * @token: a token of the type that we want to create
4355 * Returns: A newly created object whose definition is
4356 * looked up using @token in the @image image
4359 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4363 class = mono_class_get (image, token);
4365 return mono_object_new (domain, class);
4370 * mono_object_clone:
4371 * @obj: the object to clone
4373 * Returns: A newly created object who is a shallow copy of @obj
4376 mono_object_clone (MonoObject *obj)
4379 int size = obj->vtable->klass->instance_size;
4381 o = mono_object_allocate (size, obj->vtable);
4383 if (obj->vtable->klass->has_references) {
4384 mono_gc_wbarrier_object_copy (o, obj);
4386 int size = obj->vtable->klass->instance_size;
4387 /* do not copy the sync state */
4388 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4390 if (G_UNLIKELY (profile_allocs))
4391 mono_profiler_allocation (o, obj->vtable->klass);
4393 if (obj->vtable->klass->has_finalize)
4394 mono_object_register_finalizer (o);
4399 * mono_array_full_copy:
4400 * @src: source array to copy
4401 * @dest: destination array
4403 * Copies the content of one array to another with exactly the same type and size.
4406 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4409 MonoClass *klass = src->obj.vtable->klass;
4411 MONO_ARCH_SAVE_REGS;
4413 g_assert (klass == dest->obj.vtable->klass);
4415 size = mono_array_length (src);
4416 g_assert (size == mono_array_length (dest));
4417 size *= mono_array_element_size (klass);
4419 if (klass->element_class->valuetype) {
4420 if (klass->element_class->has_references)
4421 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4423 memcpy (&dest->vector, &src->vector, size);
4425 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4428 memcpy (&dest->vector, &src->vector, size);
4433 * mono_array_clone_in_domain:
4434 * @domain: the domain in which the array will be cloned into
4435 * @array: the array to clone
4437 * This routine returns a copy of the array that is hosted on the
4438 * specified MonoDomain.
4441 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4446 MonoClass *klass = array->obj.vtable->klass;
4448 MONO_ARCH_SAVE_REGS;
4450 if (array->bounds == NULL) {
4451 size = mono_array_length (array);
4452 o = mono_array_new_full (domain, klass, &size, NULL);
4454 size *= mono_array_element_size (klass);
4456 if (klass->element_class->valuetype) {
4457 if (klass->element_class->has_references)
4458 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4460 memcpy (&o->vector, &array->vector, size);
4462 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4465 memcpy (&o->vector, &array->vector, size);
4470 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4471 size = mono_array_element_size (klass);
4472 for (i = 0; i < klass->rank; ++i) {
4473 sizes [i] = array->bounds [i].length;
4474 size *= array->bounds [i].length;
4475 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4477 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4479 if (klass->element_class->valuetype) {
4480 if (klass->element_class->has_references)
4481 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4483 memcpy (&o->vector, &array->vector, size);
4485 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4488 memcpy (&o->vector, &array->vector, size);
4496 * @array: the array to clone
4498 * Returns: A newly created array who is a shallow copy of @array
4501 mono_array_clone (MonoArray *array)
4503 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4506 /* helper macros to check for overflow when calculating the size of arrays */
4507 #ifdef MONO_BIG_ARRAYS
4508 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4509 #define MYGUINT_MAX MYGUINT64_MAX
4510 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4511 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4512 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4513 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4514 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4516 #define MYGUINT32_MAX 4294967295U
4517 #define MYGUINT_MAX MYGUINT32_MAX
4518 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4519 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4520 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4521 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4522 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4526 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4530 byte_len = mono_array_element_size (class);
4531 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4534 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4536 byte_len += sizeof (MonoArray);
4544 * mono_array_new_full:
4545 * @domain: domain where the object is created
4546 * @array_class: array class
4547 * @lengths: lengths for each dimension in the array
4548 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4550 * This routine creates a new array objects with the given dimensions,
4551 * lower bounds and type.
4554 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4556 uintptr_t byte_len, len, bounds_size;
4559 MonoArrayBounds *bounds;
4563 if (!array_class->inited)
4564 mono_class_init (array_class);
4568 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4569 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4571 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4575 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4577 for (i = 0; i < array_class->rank; ++i) {
4578 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4580 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4581 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4586 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4587 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4591 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4592 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4593 byte_len = (byte_len + 3) & ~3;
4594 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4595 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4596 byte_len += bounds_size;
4599 * Following three lines almost taken from mono_object_new ():
4600 * they need to be kept in sync.
4602 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4603 #ifndef HAVE_SGEN_GC
4604 if (!array_class->has_references) {
4605 o = mono_object_allocate_ptrfree (byte_len, vtable);
4606 #if NEED_TO_ZERO_PTRFREE
4607 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4609 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4610 o = mono_object_allocate_spec (byte_len, vtable);
4612 o = mono_object_allocate (byte_len, vtable);
4615 array = (MonoArray*)o;
4616 array->max_length = len;
4619 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4620 array->bounds = bounds;
4624 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4626 o = mono_gc_alloc_vector (vtable, byte_len, len);
4627 array = (MonoArray*)o;
4628 mono_stats.new_object_count++;
4630 bounds = array->bounds;
4634 for (i = 0; i < array_class->rank; ++i) {
4635 bounds [i].length = lengths [i];
4637 bounds [i].lower_bound = lower_bounds [i];
4641 if (G_UNLIKELY (profile_allocs))
4642 mono_profiler_allocation (o, array_class);
4649 * @domain: domain where the object is created
4650 * @eclass: element class
4651 * @n: number of array elements
4653 * This routine creates a new szarray with @n elements of type @eclass.
4656 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4660 MONO_ARCH_SAVE_REGS;
4662 ac = mono_array_class_get (eclass, 1);
4665 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4669 * mono_array_new_specific:
4670 * @vtable: a vtable in the appropriate domain for an initialized class
4671 * @n: number of array elements
4673 * This routine is a fast alternative to mono_array_new() for code which
4674 * can be sure about the domain it operates in.
4677 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4683 MONO_ARCH_SAVE_REGS;
4685 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4690 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4691 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4694 #ifndef HAVE_SGEN_GC
4695 if (!vtable->klass->has_references) {
4696 o = mono_object_allocate_ptrfree (byte_len, vtable);
4697 #if NEED_TO_ZERO_PTRFREE
4698 ((MonoArray*)o)->bounds = NULL;
4699 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4701 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4702 o = mono_object_allocate_spec (byte_len, vtable);
4704 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4705 o = mono_object_allocate (byte_len, vtable);
4708 ao = (MonoArray *)o;
4711 o = mono_gc_alloc_vector (vtable, byte_len, n);
4713 mono_stats.new_object_count++;
4716 if (G_UNLIKELY (profile_allocs))
4717 mono_profiler_allocation (o, vtable->klass);
4723 * mono_string_new_utf16:
4724 * @text: a pointer to an utf16 string
4725 * @len: the length of the string
4727 * Returns: A newly created string object which contains @text.
4730 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4734 s = mono_string_new_size (domain, len);
4735 g_assert (s != NULL);
4737 memcpy (mono_string_chars (s), text, len * 2);
4743 * mono_string_new_size:
4744 * @text: a pointer to an utf16 string
4745 * @len: the length of the string
4747 * Returns: A newly created string object of @len
4750 mono_string_new_size (MonoDomain *domain, gint32 len)
4754 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4756 /* overflow ? can't fit it, can't allocate it! */
4758 mono_gc_out_of_memory (-1);
4760 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4763 #ifndef HAVE_SGEN_GC
4764 s = mono_object_allocate_ptrfree (size, vtable);
4768 s = mono_gc_alloc_string (vtable, size, len);
4770 #if NEED_TO_ZERO_PTRFREE
4773 if (G_UNLIKELY (profile_allocs))
4774 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4780 * mono_string_new_len:
4781 * @text: a pointer to an utf8 string
4782 * @length: number of bytes in @text to consider
4784 * Returns: A newly created string object which contains @text.
4787 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4789 GError *error = NULL;
4790 MonoString *o = NULL;
4792 glong items_written;
4794 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4797 o = mono_string_new_utf16 (domain, ut, items_written);
4799 g_error_free (error);
4808 * @text: a pointer to an utf8 string
4810 * Returns: A newly created string object which contains @text.
4813 mono_string_new (MonoDomain *domain, const char *text)
4815 GError *error = NULL;
4816 MonoString *o = NULL;
4818 glong items_written;
4823 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4826 o = mono_string_new_utf16 (domain, ut, items_written);
4828 g_error_free (error);
4831 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4836 MonoString *o = NULL;
4838 if (!g_utf8_validate (text, -1, &end))
4841 len = g_utf8_strlen (text, -1);
4842 o = mono_string_new_size (domain, len);
4843 str = mono_string_chars (o);
4845 while (text < end) {
4846 *str++ = g_utf8_get_char (text);
4847 text = g_utf8_next_char (text);
4854 * mono_string_new_wrapper:
4855 * @text: pointer to utf8 characters.
4857 * Helper function to create a string object from @text in the current domain.
4860 mono_string_new_wrapper (const char *text)
4862 MonoDomain *domain = mono_domain_get ();
4864 MONO_ARCH_SAVE_REGS;
4867 return mono_string_new (domain, text);
4874 * @class: the class of the value
4875 * @value: a pointer to the unboxed data
4877 * Returns: A newly created object which contains @value.
4880 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4886 g_assert (class->valuetype);
4887 if (mono_class_is_nullable (class))
4888 return mono_nullable_box (value, class);
4890 vtable = mono_class_vtable (domain, class);
4893 size = mono_class_instance_size (class);
4894 res = mono_object_new_alloc_specific (vtable);
4895 if (G_UNLIKELY (profile_allocs))
4896 mono_profiler_allocation (res, class);
4898 size = size - sizeof (MonoObject);
4901 g_assert (size == mono_class_value_size (class, NULL));
4902 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4904 #if NO_UNALIGNED_ACCESS
4905 memcpy ((char *)res + sizeof (MonoObject), value, size);
4909 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4912 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4915 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4918 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4921 memcpy ((char *)res + sizeof (MonoObject), value, size);
4925 if (class->has_finalize)
4926 mono_object_register_finalizer (res);
4932 * @dest: destination pointer
4933 * @src: source pointer
4934 * @klass: a valuetype class
4936 * Copy a valuetype from @src to @dest. This function must be used
4937 * when @klass contains references fields.
4940 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4942 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4946 * mono_value_copy_array:
4947 * @dest: destination array
4948 * @dest_idx: index in the @dest array
4949 * @src: source pointer
4950 * @count: number of items
4952 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4953 * This function must be used when @klass contains references fields.
4954 * Overlap is handled.
4957 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4959 int size = mono_array_element_size (dest->obj.vtable->klass);
4960 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4961 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4962 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4966 * mono_object_get_domain:
4967 * @obj: object to query
4969 * Returns: the MonoDomain where the object is hosted
4972 mono_object_get_domain (MonoObject *obj)
4974 return mono_object_domain (obj);
4978 * mono_object_get_class:
4979 * @obj: object to query
4981 * Returns: the MonOClass of the object.
4984 mono_object_get_class (MonoObject *obj)
4986 return mono_object_class (obj);
4989 * mono_object_get_size:
4990 * @o: object to query
4992 * Returns: the size, in bytes, of @o
4995 mono_object_get_size (MonoObject* o)
4997 MonoClass* klass = mono_object_class (o);
4998 if (klass == mono_defaults.string_class) {
4999 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5000 } else if (o->vtable->rank) {
5001 MonoArray *array = (MonoArray*)o;
5002 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5003 if (array->bounds) {
5006 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5010 return mono_class_instance_size (klass);
5015 * mono_object_unbox:
5016 * @obj: object to unbox
5018 * Returns: a pointer to the start of the valuetype boxed in this
5021 * This method will assert if the object passed is not a valuetype.
5024 mono_object_unbox (MonoObject *obj)
5026 /* add assert for valuetypes? */
5027 g_assert (obj->vtable->klass->valuetype);
5028 return ((char*)obj) + sizeof (MonoObject);
5032 * mono_object_isinst:
5034 * @klass: a pointer to a class
5036 * Returns: @obj if @obj is derived from @klass
5039 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5042 mono_class_init (klass);
5044 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5045 return mono_object_isinst_mbyref (obj, klass);
5050 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5054 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5063 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5064 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5068 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5069 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5072 MonoClass *oklass = vt->klass;
5073 if ((oklass == mono_defaults.transparent_proxy_class))
5074 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5076 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5080 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5082 MonoDomain *domain = mono_domain_get ();
5084 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5085 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5086 MonoMethod *im = NULL;
5089 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5090 im = mono_object_get_virtual_method (rp, im);
5093 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5096 res = mono_runtime_invoke (im, rp, pa, NULL);
5098 if (*(MonoBoolean *) mono_object_unbox(res)) {
5099 /* Update the vtable of the remote type, so it can safely cast to this new type */
5100 mono_upgrade_remote_class (domain, obj, klass);
5109 * mono_object_castclass_mbyref:
5111 * @klass: a pointer to a class
5113 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5116 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5118 if (!obj) return NULL;
5119 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5121 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5123 "InvalidCastException"));
5128 MonoDomain *orig_domain;
5134 str_lookup (MonoDomain *domain, gpointer user_data)
5136 LDStrInfo *info = user_data;
5137 if (info->res || domain == info->orig_domain)
5139 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5145 mono_string_get_pinned (MonoString *str)
5149 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5150 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5151 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5152 news->length = mono_string_length (str);
5157 #define mono_string_get_pinned(str) (str)
5161 mono_string_is_interned_lookup (MonoString *str, int insert)
5163 MonoGHashTable *ldstr_table;
5167 domain = ((MonoObject *)str)->vtable->domain;
5168 ldstr_table = domain->ldstr_table;
5170 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5175 str = mono_string_get_pinned (str);
5176 mono_g_hash_table_insert (ldstr_table, str, str);
5180 LDStrInfo ldstr_info;
5181 ldstr_info.orig_domain = domain;
5182 ldstr_info.ins = str;
5183 ldstr_info.res = NULL;
5185 mono_domain_foreach (str_lookup, &ldstr_info);
5186 if (ldstr_info.res) {
5188 * the string was already interned in some other domain:
5189 * intern it in the current one as well.
5191 mono_g_hash_table_insert (ldstr_table, str, str);
5201 * mono_string_is_interned:
5202 * @o: String to probe
5204 * Returns whether the string has been interned.
5207 mono_string_is_interned (MonoString *o)
5209 return mono_string_is_interned_lookup (o, FALSE);
5213 * mono_string_intern:
5214 * @o: String to intern
5216 * Interns the string passed.
5217 * Returns: The interned string.
5220 mono_string_intern (MonoString *str)
5222 return mono_string_is_interned_lookup (str, TRUE);
5227 * @domain: the domain where the string will be used.
5228 * @image: a metadata context
5229 * @idx: index into the user string table.
5231 * Implementation for the ldstr opcode.
5232 * Returns: a loaded string from the @image/@idx combination.
5235 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5237 MONO_ARCH_SAVE_REGS;
5239 if (image->dynamic) {
5240 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5243 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5244 return NULL; /*FIXME we should probably be raising an exception here*/
5245 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5250 * mono_ldstr_metadata_sig
5251 * @domain: the domain for the string
5252 * @sig: the signature of a metadata string
5254 * Returns: a MonoString for a string stored in the metadata
5257 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5259 const char *str = sig;
5260 MonoString *o, *interned;
5263 len2 = mono_metadata_decode_blob_size (str, &str);
5266 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5267 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5270 guint16 *p2 = (guint16*)mono_string_chars (o);
5271 for (i = 0; i < len2; ++i) {
5272 *p2 = GUINT16_FROM_LE (*p2);
5278 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5280 /* o will get garbage collected */
5284 o = mono_string_get_pinned (o);
5285 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5292 * mono_string_to_utf8:
5293 * @s: a System.String
5295 * Returns the UTF8 representation for @s.
5296 * The resulting buffer needs to be freed with mono_free().
5298 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5301 mono_string_to_utf8 (MonoString *s)
5304 char *result = mono_string_to_utf8_checked (s, &error);
5306 if (!mono_error_ok (&error))
5307 mono_error_raise_exception (&error);
5312 * mono_string_to_utf8_checked:
5313 * @s: a System.String
5314 * @error: a MonoError.
5316 * Converts a MonoString to its UTF8 representation. May fail; check
5317 * @error to determine whether the conversion was successful.
5318 * The resulting buffer should be freed with mono_free().
5321 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5325 GError *gerror = NULL;
5327 mono_error_init (error);
5333 return g_strdup ("");
5335 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5337 mono_error_set_argument (error, "string", "%s", gerror->message);
5338 g_error_free (gerror);
5341 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5342 if (s->length > written) {
5343 /* allocate the total length and copy the part of the string that has been converted */
5344 char *as2 = g_malloc0 (s->length);
5345 memcpy (as2, as, written);
5354 * mono_string_to_utf16:
5357 * Return an null-terminated array of the utf-16 chars
5358 * contained in @s. The result must be freed with g_free().
5359 * This is a temporary helper until our string implementation
5360 * is reworked to always include the null terminating char.
5363 mono_string_to_utf16 (MonoString *s)
5370 as = g_malloc ((s->length * 2) + 2);
5371 as [(s->length * 2)] = '\0';
5372 as [(s->length * 2) + 1] = '\0';
5375 return (gunichar2 *)(as);
5378 memcpy (as, mono_string_chars(s), s->length * 2);
5379 return (gunichar2 *)(as);
5383 * mono_string_from_utf16:
5384 * @data: the UTF16 string (LPWSTR) to convert
5386 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5388 * Returns: a MonoString.
5391 mono_string_from_utf16 (gunichar2 *data)
5393 MonoDomain *domain = mono_domain_get ();
5399 while (data [len]) len++;
5401 return mono_string_new_utf16 (domain, data, len);
5406 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5412 r = mono_string_to_utf8_checked (s, error);
5413 if (!mono_error_ok (error))
5419 len = strlen (r) + 1;
5421 mp_s = mono_mempool_alloc (mp, len);
5423 mp_s = mono_image_alloc (image, len);
5425 memcpy (mp_s, r, len);
5433 * mono_string_to_utf8_image:
5434 * @s: a System.String
5436 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5439 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5441 return mono_string_to_utf8_internal (NULL, image, s, error);
5445 * mono_string_to_utf8_mp:
5446 * @s: a System.String
5448 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5451 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5453 return mono_string_to_utf8_internal (mp, NULL, s, error);
5457 default_ex_handler (MonoException *ex)
5459 MonoObject *o = (MonoObject*)ex;
5460 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5464 static MonoExceptionFunc ex_handler = default_ex_handler;
5467 * mono_install_handler:
5468 * @func: exception handler
5470 * This is an internal JIT routine used to install the handler for exceptions
5474 mono_install_handler (MonoExceptionFunc func)
5476 ex_handler = func? func: default_ex_handler;
5480 * mono_raise_exception:
5481 * @ex: exception object
5483 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5486 mono_raise_exception (MonoException *ex)
5489 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5490 * that will cause gcc to omit the function epilog, causing problems when
5491 * the JIT tries to walk the stack, since the return address on the stack
5492 * will point into the next function in the executable, not this one.
5495 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5496 MonoInternalThread *thread = mono_thread_internal_current ();
5497 g_assert (ex->object.vtable->domain == mono_domain_get ());
5498 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5505 * mono_wait_handle_new:
5506 * @domain: Domain where the object will be created
5507 * @handle: Handle for the wait handle
5509 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5512 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5514 MonoWaitHandle *res;
5515 gpointer params [1];
5516 static MonoMethod *handle_set;
5518 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5520 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5522 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5524 params [0] = &handle;
5525 mono_runtime_invoke (handle_set, res, params, NULL);
5531 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5533 static MonoClassField *f_os_handle;
5534 static MonoClassField *f_safe_handle;
5536 if (!f_os_handle && !f_safe_handle) {
5537 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5538 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5543 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5547 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5554 mono_runtime_capture_context (MonoDomain *domain)
5556 RuntimeInvokeFunction runtime_invoke;
5558 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5559 MonoMethod *method = mono_get_context_capture_method ();
5560 MonoMethod *wrapper;
5563 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5564 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5565 domain->capture_context_method = mono_compile_method (method);
5568 runtime_invoke = domain->capture_context_runtime_invoke;
5570 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5573 * mono_async_result_new:
5574 * @domain:domain where the object will be created.
5575 * @handle: wait handle.
5576 * @state: state to pass to AsyncResult
5577 * @data: C closure data.
5579 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5580 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5584 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5586 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5587 MonoObject *context = mono_runtime_capture_context (domain);
5588 /* we must capture the execution context from the original thread */
5590 MONO_OBJECT_SETREF (res, execution_context, context);
5591 /* note: result may be null if the flow is suppressed */
5595 MONO_OBJECT_SETREF (res, object_data, object_data);
5596 MONO_OBJECT_SETREF (res, async_state, state);
5598 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5600 res->sync_completed = FALSE;
5601 res->completed = FALSE;
5607 mono_message_init (MonoDomain *domain,
5608 MonoMethodMessage *this,
5609 MonoReflectionMethod *method,
5610 MonoArray *out_args)
5612 static MonoClass *object_array_klass;
5613 static MonoClass *byte_array_klass;
5614 static MonoClass *string_array_klass;
5615 MonoMethodSignature *sig = mono_method_signature (method->method);
5621 if (!object_array_klass) {
5624 klass = mono_array_class_get (mono_defaults.object_class, 1);
5627 mono_memory_barrier ();
5628 object_array_klass = klass;
5630 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5633 mono_memory_barrier ();
5634 byte_array_klass = klass;
5636 klass = mono_array_class_get (mono_defaults.string_class, 1);
5639 mono_memory_barrier ();
5640 string_array_klass = klass;
5643 MONO_OBJECT_SETREF (this, method, method);
5645 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5646 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5647 this->async_result = NULL;
5648 this->call_type = CallType_Sync;
5650 names = g_new (char *, sig->param_count);
5651 mono_method_get_param_names (method->method, (const char **) names);
5652 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5654 for (i = 0; i < sig->param_count; i++) {
5655 name = mono_string_new (domain, names [i]);
5656 mono_array_setref (this->names, i, name);
5660 for (i = 0, j = 0; i < sig->param_count; i++) {
5661 if (sig->params [i]->byref) {
5663 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5664 mono_array_setref (this->args, i, arg);
5668 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5672 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5675 mono_array_set (this->arg_types, guint8, i, arg_type);
5680 * mono_remoting_invoke:
5681 * @real_proxy: pointer to a RealProxy object
5682 * @msg: The MonoMethodMessage to execute
5683 * @exc: used to store exceptions
5684 * @out_args: used to store output arguments
5686 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5687 * IMessage interface and it is not trivial to extract results from there. So
5688 * we call an helper method PrivateInvoke instead of calling
5689 * RealProxy::Invoke() directly.
5691 * Returns: the result object.
5694 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5695 MonoObject **exc, MonoArray **out_args)
5697 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5700 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5703 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5705 real_proxy->vtable->domain->private_invoke_method = im;
5708 pa [0] = real_proxy;
5713 return mono_runtime_invoke (im, NULL, pa, exc);
5717 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5718 MonoObject **exc, MonoArray **out_args)
5720 static MonoClass *object_array_klass;
5723 MonoMethodSignature *sig;
5725 int i, j, outarg_count = 0;
5727 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5729 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5730 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5731 target = tp->rp->unwrapped_server;
5733 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5737 domain = mono_domain_get ();
5738 method = msg->method->method;
5739 sig = mono_method_signature (method);
5741 for (i = 0; i < sig->param_count; i++) {
5742 if (sig->params [i]->byref)
5746 if (!object_array_klass) {
5749 klass = mono_array_class_get (mono_defaults.object_class, 1);
5752 mono_memory_barrier ();
5753 object_array_klass = klass;
5756 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5757 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5760 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5762 for (i = 0, j = 0; i < sig->param_count; i++) {
5763 if (sig->params [i]->byref) {
5765 arg = mono_array_get (msg->args, gpointer, i);
5766 mono_array_setref (*out_args, j, arg);
5775 * mono_object_to_string:
5777 * @exc: Any exception thrown by ToString (). May be NULL.
5779 * Returns: the result of calling ToString () on an object.
5782 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5784 static MonoMethod *to_string = NULL;
5790 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5792 method = mono_object_get_virtual_method (obj, to_string);
5794 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5798 * mono_print_unhandled_exception:
5799 * @exc: The exception
5801 * Prints the unhandled exception.
5804 mono_print_unhandled_exception (MonoObject *exc)
5807 char *message = (char*)"";
5808 gboolean free_message = FALSE;
5811 str = mono_object_to_string (exc, NULL);
5813 message = mono_string_to_utf8_checked (str, &error);
5814 if (!mono_error_ok (&error)) {
5815 mono_error_cleanup (&error);
5816 message = (char *) "";
5818 free_message = TRUE;
5823 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5824 * exc->vtable->klass->name, message);
5826 g_printerr ("\nUnhandled Exception: %s\n", message);
5833 * mono_delegate_ctor:
5834 * @this: pointer to an uninitialized delegate object
5835 * @target: target object
5836 * @addr: pointer to native code
5839 * Initialize a delegate and sets a specific method, not the one
5840 * associated with addr. This is useful when sharing generic code.
5841 * In that case addr will most probably not be associated with the
5842 * correct instantiation of the method.
5845 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5847 MonoDelegate *delegate = (MonoDelegate *)this;
5854 delegate->method = method;
5856 class = this->vtable->klass;
5857 mono_stats.delegate_creations++;
5859 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5861 method = mono_marshal_get_remoting_invoke (method);
5862 delegate->method_ptr = mono_compile_method (method);
5863 MONO_OBJECT_SETREF (delegate, target, target);
5864 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5865 method = mono_marshal_get_unbox_wrapper (method);
5866 delegate->method_ptr = mono_compile_method (method);
5867 MONO_OBJECT_SETREF (delegate, target, target);
5869 delegate->method_ptr = addr;
5870 MONO_OBJECT_SETREF (delegate, target, target);
5873 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5877 * mono_delegate_ctor:
5878 * @this: pointer to an uninitialized delegate object
5879 * @target: target object
5880 * @addr: pointer to native code
5882 * This is used to initialize a delegate.
5885 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5887 MonoDomain *domain = mono_domain_get ();
5889 MonoMethod *method = NULL;
5893 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5894 method = ji->method;
5895 g_assert (!method->klass->generic_container);
5898 mono_delegate_ctor_with_method (this, target, addr, method);
5902 * mono_method_call_message_new:
5903 * @method: method to encapsulate
5904 * @params: parameters to the method
5905 * @invoke: optional, delegate invoke.
5906 * @cb: async callback delegate.
5907 * @state: state passed to the async callback.
5909 * Translates arguments pointers into a MonoMethodMessage.
5912 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5913 MonoDelegate **cb, MonoObject **state)
5915 MonoDomain *domain = mono_domain_get ();
5916 MonoMethodSignature *sig = mono_method_signature (method);
5917 MonoMethodMessage *msg;
5920 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5923 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5924 count = sig->param_count - 2;
5926 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5927 count = sig->param_count;
5930 for (i = 0; i < count; i++) {
5935 if (sig->params [i]->byref)
5936 vpos = *((gpointer *)params [i]);
5940 type = sig->params [i]->type;
5941 class = mono_class_from_mono_type (sig->params [i]);
5943 if (class->valuetype)
5944 arg = mono_value_box (domain, class, vpos);
5946 arg = *((MonoObject **)vpos);
5948 mono_array_setref (msg->args, i, arg);
5951 if (cb != NULL && state != NULL) {
5952 *cb = *((MonoDelegate **)params [i]);
5954 *state = *((MonoObject **)params [i]);
5961 * mono_method_return_message_restore:
5963 * Restore results from message based processing back to arguments pointers
5966 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5968 MonoMethodSignature *sig = mono_method_signature (method);
5969 int i, j, type, size, out_len;
5971 if (out_args == NULL)
5973 out_len = mono_array_length (out_args);
5977 for (i = 0, j = 0; i < sig->param_count; i++) {
5978 MonoType *pt = sig->params [i];
5983 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5985 arg = mono_array_get (out_args, gpointer, j);
5988 g_assert (type != MONO_TYPE_VOID);
5990 if (MONO_TYPE_IS_REFERENCE (pt)) {
5991 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5994 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5995 size = mono_class_value_size (class, NULL);
5996 if (class->has_references)
5997 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5999 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6001 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6002 memset (*((gpointer *)params [i]), 0, size);
6012 * mono_load_remote_field:
6013 * @this: pointer to an object
6014 * @klass: klass of the object containing @field
6015 * @field: the field to load
6016 * @res: a storage to store the result
6018 * This method is called by the runtime on attempts to load fields of
6019 * transparent proxy objects. @this points to such TP, @klass is the class of
6020 * the object containing @field. @res is a storage location which can be
6021 * used to store the result.
6023 * Returns: an address pointing to the value of field.
6026 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6028 static MonoMethod *getter = NULL;
6029 MonoDomain *domain = mono_domain_get ();
6030 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6031 MonoClass *field_class;
6032 MonoMethodMessage *msg;
6033 MonoArray *out_args;
6037 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6038 g_assert (res != NULL);
6040 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6041 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6046 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6050 field_class = mono_class_from_mono_type (field->type);
6052 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6053 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6054 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6056 full_name = mono_type_get_full_name (klass);
6057 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6058 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6061 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6063 if (exc) mono_raise_exception ((MonoException *)exc);
6065 if (mono_array_length (out_args) == 0)
6068 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6070 if (field_class->valuetype) {
6071 return ((char *)*res) + sizeof (MonoObject);
6077 * mono_load_remote_field_new:
6082 * Missing documentation.
6085 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6087 static MonoMethod *getter = NULL;
6088 MonoDomain *domain = mono_domain_get ();
6089 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6090 MonoClass *field_class;
6091 MonoMethodMessage *msg;
6092 MonoArray *out_args;
6093 MonoObject *exc, *res;
6096 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6098 field_class = mono_class_from_mono_type (field->type);
6100 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6102 if (field_class->valuetype) {
6103 res = mono_object_new (domain, field_class);
6104 val = ((gchar *) res) + sizeof (MonoObject);
6108 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6113 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6117 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6118 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6120 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6122 full_name = mono_type_get_full_name (klass);
6123 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6124 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6127 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6129 if (exc) mono_raise_exception ((MonoException *)exc);
6131 if (mono_array_length (out_args) == 0)
6134 res = mono_array_get (out_args, MonoObject *, 0);
6140 * mono_store_remote_field:
6141 * @this: pointer to an object
6142 * @klass: klass of the object containing @field
6143 * @field: the field to load
6144 * @val: the value/object to store
6146 * This method is called by the runtime on attempts to store fields of
6147 * transparent proxy objects. @this points to such TP, @klass is the class of
6148 * the object containing @field. @val is the new value to store in @field.
6151 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6153 static MonoMethod *setter = NULL;
6154 MonoDomain *domain = mono_domain_get ();
6155 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6156 MonoClass *field_class;
6157 MonoMethodMessage *msg;
6158 MonoArray *out_args;
6163 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6165 field_class = mono_class_from_mono_type (field->type);
6167 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6168 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6169 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6174 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6178 if (field_class->valuetype)
6179 arg = mono_value_box (domain, field_class, val);
6181 arg = *((MonoObject **)val);
6184 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6185 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6187 full_name = mono_type_get_full_name (klass);
6188 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6189 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6190 mono_array_setref (msg->args, 2, arg);
6193 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6195 if (exc) mono_raise_exception ((MonoException *)exc);
6199 * mono_store_remote_field_new:
6205 * Missing documentation
6208 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6210 static MonoMethod *setter = NULL;
6211 MonoDomain *domain = mono_domain_get ();
6212 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6213 MonoClass *field_class;
6214 MonoMethodMessage *msg;
6215 MonoArray *out_args;
6219 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6221 field_class = mono_class_from_mono_type (field->type);
6223 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6224 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6225 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6230 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6234 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6235 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6237 full_name = mono_type_get_full_name (klass);
6238 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6239 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6240 mono_array_setref (msg->args, 2, arg);
6243 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6245 if (exc) mono_raise_exception ((MonoException *)exc);
6249 * mono_create_ftnptr:
6251 * Given a function address, create a function descriptor for it.
6252 * This is only needed on some platforms.
6255 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6257 return callbacks.create_ftnptr (domain, addr);
6261 * mono_get_addr_from_ftnptr:
6263 * Given a pointer to a function descriptor, return the function address.
6264 * This is only needed on some platforms.
6267 mono_get_addr_from_ftnptr (gpointer descr)
6269 return callbacks.get_addr_from_ftnptr (descr);
6273 * mono_string_chars:
6276 * Returns a pointer to the UCS16 characters stored in the MonoString
6279 mono_string_chars (MonoString *s)
6285 * mono_string_length:
6288 * Returns the lenght in characters of the string
6291 mono_string_length (MonoString *s)
6297 * mono_array_length:
6298 * @array: a MonoArray*
6300 * Returns the total number of elements in the array. This works for
6301 * both vectors and multidimensional arrays.
6304 mono_array_length (MonoArray *array)
6306 return array->max_length;
6310 * mono_array_addr_with_size:
6311 * @array: a MonoArray*
6312 * @size: size of the array elements
6313 * @idx: index into the array
6315 * Returns the address of the @idx element in the array.
6318 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6320 return ((char*)(array)->vector) + size * idx;