2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
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/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internal.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-error-internals.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include "cominterop.h"
48 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
51 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
54 free_main_args (void);
57 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
60 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
61 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
62 static mono_mutex_t ldstr_section;
65 mono_runtime_object_init (MonoObject *this)
67 MonoMethod *method = NULL;
68 MonoClass *klass = this->vtable->klass;
70 method = mono_class_get_method_from_name (klass, ".ctor", 0);
72 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
74 if (method->klass->valuetype)
75 this = mono_object_unbox (this);
76 mono_runtime_invoke (method, this, NULL, NULL);
79 /* The pseudo algorithm for type initialization from the spec
80 Note it doesn't say anything about domains - only threads.
82 2. If the type is initialized you are done.
83 2.1. If the type is not yet initialized, try to take an
85 2.2. If successful, record this thread as responsible for
86 initializing the type and proceed to step 2.3.
87 2.2.1. If not, see whether this thread or any thread
88 waiting for this thread to complete already holds the lock.
89 2.2.2. If so, return since blocking would create a deadlock. This thread
90 will now see an incompletely initialized state for the type,
91 but no deadlock will arise.
92 2.2.3 If not, block until the type is initialized then return.
93 2.3 Initialize the parent type and then all interfaces implemented
95 2.4 Execute the type initialization code for this type.
96 2.5 Mark the type as initialized, release the initialization lock,
97 awaken any threads waiting for this type to be initialized,
104 guint32 initializing_tid;
105 guint32 waiting_count;
107 mono_mutex_t initialization_section;
108 } TypeInitializationLock;
110 /* for locking access to type_initialization_hash and blocked_thread_hash */
111 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
112 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
113 static mono_mutex_t type_initialization_section;
117 mono_type_init_lock (TypeInitializationLock *lock)
120 mono_mutex_lock (&lock->initialization_section);
121 MONO_FINISH_TRY_BLOCKING;
125 mono_type_init_unlock (TypeInitializationLock *lock)
127 mono_mutex_unlock (&lock->initialization_section);
130 /* from vtable to lock */
131 static GHashTable *type_initialization_hash;
133 /* from thread id to thread id being waited on */
134 static GHashTable *blocked_thread_hash;
137 static MonoThread *main_thread;
139 /* Functions supplied by the runtime */
140 static MonoRuntimeCallbacks callbacks;
143 * mono_thread_set_main:
144 * @thread: thread to set as the main thread
146 * This function can be used to instruct the runtime to treat @thread
147 * as the main thread, ie, the thread that would normally execute the Main()
148 * method. This basically means that at the end of @thread, the runtime will
149 * wait for the existing foreground threads to quit and other such details.
152 mono_thread_set_main (MonoThread *thread)
154 static gboolean registered = FALSE;
157 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
161 main_thread = thread;
165 mono_thread_get_main (void)
171 mono_type_initialization_init (void)
173 mono_mutex_init_recursive (&type_initialization_section);
174 type_initialization_hash = g_hash_table_new (NULL, NULL);
175 blocked_thread_hash = g_hash_table_new (NULL, NULL);
176 mono_mutex_init_recursive (&ldstr_section);
180 mono_type_initialization_cleanup (void)
183 /* This is causing race conditions with
184 * mono_release_type_locks
186 mono_mutex_destroy (&type_initialization_section);
187 g_hash_table_destroy (type_initialization_hash);
188 type_initialization_hash = NULL;
190 mono_mutex_destroy (&ldstr_section);
191 g_hash_table_destroy (blocked_thread_hash);
192 blocked_thread_hash = NULL;
198 * get_type_init_exception_for_vtable:
200 * Return the stored type initialization exception for VTABLE.
202 static MonoException*
203 get_type_init_exception_for_vtable (MonoVTable *vtable)
205 MonoDomain *domain = vtable->domain;
206 MonoClass *klass = vtable->klass;
210 if (!vtable->init_failed)
211 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
214 * If the initializing thread was rudely aborted, the exception is not stored
218 mono_domain_lock (domain);
219 if (domain->type_init_exception_hash)
220 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
221 mono_domain_unlock (domain);
224 if (klass->name_space && *klass->name_space)
225 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
227 full_name = g_strdup (klass->name);
228 ex = mono_get_exception_type_initialization (full_name, NULL);
235 * mono_runtime_class_init:
236 * @vtable: vtable that needs to be initialized
238 * This routine calls the class constructor for @vtable.
241 mono_runtime_class_init (MonoVTable *vtable)
243 mono_runtime_class_init_full (vtable, TRUE);
247 * mono_runtime_class_init_full:
248 * @vtable that neeeds to be initialized
249 * @raise_exception is TRUE, exceptions are raised intead of returned
253 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
256 MonoException *exc_to_throw;
257 MonoMethod *method = NULL;
261 if (vtable->initialized)
265 klass = vtable->klass;
267 if (!klass->image->checked_module_cctor) {
268 mono_image_check_for_module_cctor (klass->image);
269 if (klass->image->has_module_cctor) {
271 MonoClass *module_klass;
272 MonoVTable *module_vtable;
274 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
276 exc = mono_error_convert_to_exception (&error);
278 mono_raise_exception (exc);
282 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
285 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
290 method = mono_class_get_cctor (klass);
293 MonoDomain *domain = vtable->domain;
294 TypeInitializationLock *lock;
295 guint32 tid = GetCurrentThreadId();
296 int do_initialization = 0;
297 MonoDomain *last_domain = NULL;
299 mono_type_initialization_lock ();
300 /* double check... */
301 if (vtable->initialized) {
302 mono_type_initialization_unlock ();
305 if (vtable->init_failed) {
306 mono_type_initialization_unlock ();
308 /* The type initialization already failed once, rethrow the same exception */
310 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
311 return get_type_init_exception_for_vtable (vtable);
313 lock = g_hash_table_lookup (type_initialization_hash, vtable);
315 /* This thread will get to do the initialization */
316 if (mono_domain_get () != domain) {
317 /* Transfer into the target domain */
318 last_domain = mono_domain_get ();
319 if (!mono_domain_set (domain, FALSE)) {
320 vtable->initialized = 1;
321 mono_type_initialization_unlock ();
323 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
324 return mono_get_exception_appdomain_unloaded ();
327 lock = g_malloc (sizeof(TypeInitializationLock));
328 mono_mutex_init_recursive (&lock->initialization_section);
329 lock->initializing_tid = tid;
330 lock->waiting_count = 1;
332 /* grab the vtable lock while this thread still owns type_initialization_section */
333 mono_type_init_lock (lock);
334 g_hash_table_insert (type_initialization_hash, vtable, lock);
335 do_initialization = 1;
338 TypeInitializationLock *pending_lock;
340 if (lock->initializing_tid == tid || lock->done) {
341 mono_type_initialization_unlock ();
344 /* see if the thread doing the initialization is already blocked on this thread */
345 blocked = GUINT_TO_POINTER (lock->initializing_tid);
346 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
347 if (pending_lock->initializing_tid == tid) {
348 if (!pending_lock->done) {
349 mono_type_initialization_unlock ();
352 /* the thread doing the initialization is blocked on this thread,
353 but on a lock that has already been freed. It just hasn't got
358 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
360 ++lock->waiting_count;
361 /* record the fact that we are waiting on the initializing thread */
362 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
364 mono_type_initialization_unlock ();
366 if (do_initialization) {
367 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
369 /* If the initialization failed, mark the class as unusable. */
370 /* Avoid infinite loops */
372 (klass->image == mono_defaults.corlib &&
373 !strcmp (klass->name_space, "System") &&
374 !strcmp (klass->name, "TypeInitializationException")))) {
375 vtable->init_failed = 1;
377 if (klass->name_space && *klass->name_space)
378 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
380 full_name = g_strdup (klass->name);
381 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
385 * Store the exception object so it could be thrown on subsequent
388 mono_domain_lock (domain);
389 if (!domain->type_init_exception_hash)
390 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
391 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
392 mono_domain_unlock (domain);
396 mono_domain_set (last_domain, TRUE);
398 mono_type_init_unlock (lock);
400 /* this just blocks until the initializing thread is done */
401 mono_type_init_lock (lock);
402 mono_type_init_unlock (lock);
405 mono_type_initialization_lock ();
406 if (lock->initializing_tid != tid)
407 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
408 --lock->waiting_count;
409 if (lock->waiting_count == 0) {
410 mono_mutex_destroy (&lock->initialization_section);
411 g_hash_table_remove (type_initialization_hash, vtable);
414 mono_memory_barrier ();
415 if (!vtable->init_failed)
416 vtable->initialized = 1;
417 mono_type_initialization_unlock ();
419 if (vtable->init_failed) {
420 /* Either we were the initializing thread or we waited for the initialization */
422 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
423 return get_type_init_exception_for_vtable (vtable);
426 vtable->initialized = 1;
433 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
435 MonoVTable *vtable = (MonoVTable*)key;
437 TypeInitializationLock *lock = (TypeInitializationLock*) value;
438 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
441 * Have to set this since it cannot be set by the normal code in
442 * mono_runtime_class_init (). In this case, the exception object is not stored,
443 * and get_type_init_exception_for_class () needs to be aware of this.
445 vtable->init_failed = 1;
446 mono_type_init_unlock (lock);
447 --lock->waiting_count;
448 if (lock->waiting_count == 0) {
449 mono_mutex_destroy (&lock->initialization_section);
458 mono_release_type_locks (MonoInternalThread *thread)
460 mono_type_initialization_lock ();
461 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
462 mono_type_initialization_unlock ();
466 default_trampoline (MonoMethod *method)
472 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
474 g_assert_not_reached ();
479 #ifndef DISABLE_REMOTING
482 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
484 g_error ("remoting not installed");
488 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
492 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
494 g_assert_not_reached ();
498 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
499 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
500 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
501 static MonoImtThunkBuilder imt_thunk_builder;
502 #if (MONO_IMT_SIZE > 32)
503 #error "MONO_IMT_SIZE cannot be larger than 32"
507 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
509 memcpy (&callbacks, cbs, sizeof (*cbs));
512 MonoRuntimeCallbacks*
513 mono_get_runtime_callbacks (void)
519 mono_install_trampoline (MonoTrampoline func)
521 arch_create_jit_trampoline = func? func: default_trampoline;
525 mono_install_jump_trampoline (MonoJumpTrampoline func)
527 arch_create_jump_trampoline = func? func: default_jump_trampoline;
530 #ifndef DISABLE_REMOTING
532 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
534 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
539 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
541 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
545 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
546 imt_thunk_builder = func;
549 static MonoCompileFunc default_mono_compile_method = NULL;
552 * mono_install_compile_method:
553 * @func: function to install
555 * This is a VM internal routine
558 mono_install_compile_method (MonoCompileFunc func)
560 default_mono_compile_method = func;
564 * mono_compile_method:
565 * @method: The method to compile.
567 * This JIT-compiles the method, and returns the pointer to the native code
571 mono_compile_method (MonoMethod *method)
573 if (!default_mono_compile_method) {
574 g_error ("compile method called on uninitialized runtime");
577 return default_mono_compile_method (method);
581 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
583 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
587 mono_runtime_create_delegate_trampoline (MonoClass *klass)
589 return arch_create_delegate_trampoline (mono_domain_get (), klass);
592 static MonoFreeMethodFunc default_mono_free_method = NULL;
595 * mono_install_free_method:
596 * @func: pointer to the MonoFreeMethodFunc used to release a method
598 * This is an internal VM routine, it is used for the engines to
599 * register a handler to release the resources associated with a method.
601 * Methods are freed when no more references to the delegate that holds
605 mono_install_free_method (MonoFreeMethodFunc func)
607 default_mono_free_method = func;
611 * mono_runtime_free_method:
612 * @domain; domain where the method is hosted
613 * @method: method to release
615 * This routine is invoked to free the resources associated with
616 * a method that has been JIT compiled. This is used to discard
617 * methods that were used only temporarily (for example, used in marshalling)
621 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
623 if (default_mono_free_method != NULL)
624 default_mono_free_method (domain, method);
626 mono_method_clear_object (domain, method);
628 mono_free_method (method);
632 * The vtables in the root appdomain are assumed to be reachable by other
633 * roots, and we don't use typed allocation in the other domains.
636 /* The sync block is no longer a GC pointer */
637 #define GC_HEADER_BITMAP (0)
639 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
642 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
644 MonoClassField *field;
650 max_size = mono_class_data_size (class) / sizeof (gpointer);
652 max_size = class->instance_size / sizeof (gpointer);
653 if (max_size > size) {
654 g_assert (offset <= 0);
655 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
660 /*An Ephemeron cannot be marked by sgen*/
661 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
663 memset (bitmap, 0, size / 8);
668 for (p = class; p != NULL; p = p->parent) {
669 gpointer iter = NULL;
670 while ((field = mono_class_get_fields (p, &iter))) {
674 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
676 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
679 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
682 /* FIXME: should not happen, flag as type load error */
683 if (field->type->byref)
686 if (static_fields && field->offset == -1)
690 pos = field->offset / sizeof (gpointer);
693 type = mono_type_get_underlying_type (field->type);
694 switch (type->type) {
697 case MONO_TYPE_FNPTR:
699 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
704 if (class->image != mono_defaults.corlib)
707 case MONO_TYPE_STRING:
708 case MONO_TYPE_SZARRAY:
709 case MONO_TYPE_CLASS:
710 case MONO_TYPE_OBJECT:
711 case MONO_TYPE_ARRAY:
712 g_assert ((field->offset % sizeof(gpointer)) == 0);
714 g_assert (pos < size || pos <= max_size);
715 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
716 *max_set = MAX (*max_set, pos);
718 case MONO_TYPE_GENERICINST:
719 if (!mono_type_generic_inst_is_valuetype (type)) {
720 g_assert ((field->offset % sizeof(gpointer)) == 0);
722 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
723 *max_set = MAX (*max_set, pos);
728 case MONO_TYPE_VALUETYPE: {
729 MonoClass *fclass = mono_class_from_mono_type (field->type);
730 if (fclass->has_references) {
731 /* remove the object header */
732 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
746 case MONO_TYPE_BOOLEAN:
750 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
761 * mono_class_compute_bitmap:
763 * Mono internal function to compute a bitmap of reference fields in a class.
766 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
768 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
773 * similar to the above, but sets the bits in the bitmap for any non-ref field
774 * and ignores static fields
777 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
779 MonoClassField *field;
784 max_size = class->instance_size / sizeof (gpointer);
785 if (max_size >= size) {
786 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
789 for (p = class; p != NULL; p = p->parent) {
790 gpointer iter = NULL;
791 while ((field = mono_class_get_fields (p, &iter))) {
794 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
796 /* FIXME: should not happen, flag as type load error */
797 if (field->type->byref)
800 pos = field->offset / sizeof (gpointer);
803 type = mono_type_get_underlying_type (field->type);
804 switch (type->type) {
805 #if SIZEOF_VOID_P == 8
809 case MONO_TYPE_FNPTR:
814 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
815 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
816 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
819 #if SIZEOF_VOID_P == 4
823 case MONO_TYPE_FNPTR:
828 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
829 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
830 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
836 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
837 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
838 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
841 case MONO_TYPE_BOOLEAN:
844 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
846 case MONO_TYPE_STRING:
847 case MONO_TYPE_SZARRAY:
848 case MONO_TYPE_CLASS:
849 case MONO_TYPE_OBJECT:
850 case MONO_TYPE_ARRAY:
852 case MONO_TYPE_GENERICINST:
853 if (!mono_type_generic_inst_is_valuetype (type)) {
858 case MONO_TYPE_VALUETYPE: {
859 MonoClass *fclass = mono_class_from_mono_type (field->type);
860 /* remove the object header */
861 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
865 g_assert_not_reached ();
874 * mono_class_insecure_overlapping:
875 * check if a class with explicit layout has references and non-references
876 * fields overlapping.
878 * Returns: TRUE if it is insecure to load the type.
881 mono_class_insecure_overlapping (MonoClass *klass)
885 gsize default_bitmap [4] = {0};
887 gsize default_nrbitmap [4] = {0};
888 int i, insecure = FALSE;
891 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
892 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
894 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
895 int idx = i % (sizeof (bitmap [0]) * 8);
896 if (bitmap [idx] & nrbitmap [idx]) {
901 if (bitmap != default_bitmap)
903 if (nrbitmap != default_nrbitmap)
906 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
914 mono_string_alloc (int length)
916 return mono_string_new_size (mono_domain_get (), length);
920 mono_class_compute_gc_descriptor (MonoClass *class)
924 gsize default_bitmap [4] = {0};
925 static gboolean gcj_inited = FALSE;
930 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
931 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
934 mono_loader_unlock ();
938 mono_class_init (class);
940 if (class->gc_descr_inited)
943 class->gc_descr_inited = TRUE;
944 class->gc_descr = MONO_GC_DESCRIPTOR_NULL;
946 bitmap = default_bitmap;
947 if (class == mono_defaults.string_class) {
948 class->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
949 } else if (class->rank) {
950 mono_class_compute_gc_descriptor (class->element_class);
951 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
953 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
954 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
955 class->name_space, class->name);*/
957 /* remove the object header */
958 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
959 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
960 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
961 class->name_space, class->name);*/
962 if (bitmap != default_bitmap)
966 /*static int count = 0;
969 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
970 class->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
972 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
973 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
975 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
976 if (bitmap != default_bitmap)
982 * field_is_special_static:
983 * @fklass: The MonoClass to look up.
984 * @field: The MonoClassField describing the field.
986 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
987 * SPECIAL_STATIC_NONE otherwise.
990 field_is_special_static (MonoClass *fklass, MonoClassField *field)
992 MonoCustomAttrInfo *ainfo;
994 ainfo = mono_custom_attrs_from_field (fklass, field);
997 for (i = 0; i < ainfo->num_attrs; ++i) {
998 MonoClass *klass = ainfo->attrs [i].ctor->klass;
999 if (klass->image == mono_defaults.corlib) {
1000 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1001 mono_custom_attrs_free (ainfo);
1002 return SPECIAL_STATIC_THREAD;
1004 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1005 mono_custom_attrs_free (ainfo);
1006 return SPECIAL_STATIC_CONTEXT;
1010 mono_custom_attrs_free (ainfo);
1011 return SPECIAL_STATIC_NONE;
1014 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1015 #define mix(a,b,c) { \
1016 a -= c; a ^= rot(c, 4); c += b; \
1017 b -= a; b ^= rot(a, 6); a += c; \
1018 c -= b; c ^= rot(b, 8); b += a; \
1019 a -= c; a ^= rot(c,16); c += b; \
1020 b -= a; b ^= rot(a,19); a += c; \
1021 c -= b; c ^= rot(b, 4); b += a; \
1023 #define final(a,b,c) { \
1024 c ^= b; c -= rot(b,14); \
1025 a ^= c; a -= rot(c,11); \
1026 b ^= a; b -= rot(a,25); \
1027 c ^= b; c -= rot(b,16); \
1028 a ^= c; a -= rot(c,4); \
1029 b ^= a; b -= rot(a,14); \
1030 c ^= b; c -= rot(b,24); \
1034 * mono_method_get_imt_slot:
1036 * The IMT slot is embedded into AOTed code, so this must return the same value
1037 * for the same method across all executions. This means:
1038 * - pointers shouldn't be used as hash values.
1039 * - mono_metadata_str_hash () should be used for hashing strings.
1042 mono_method_get_imt_slot (MonoMethod *method)
1044 MonoMethodSignature *sig;
1046 guint32 *hashes_start, *hashes;
1050 /* This can be used to stress tests the collision code */
1054 * We do this to simplify generic sharing. It will hurt
1055 * performance in cases where a class implements two different
1056 * instantiations of the same generic interface.
1057 * The code in build_imt_slots () depends on this.
1059 if (method->is_inflated)
1060 method = ((MonoMethodInflated*)method)->declaring;
1062 sig = mono_method_signature (method);
1063 hashes_count = sig->param_count + 4;
1064 hashes_start = malloc (hashes_count * sizeof (guint32));
1065 hashes = hashes_start;
1067 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1068 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1069 method->klass->name_space, method->klass->name, method->name);
1072 /* Initialize hashes */
1073 hashes [0] = mono_metadata_str_hash (method->klass->name);
1074 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1075 hashes [2] = mono_metadata_str_hash (method->name);
1076 hashes [3] = mono_metadata_type_hash (sig->ret);
1077 for (i = 0; i < sig->param_count; i++) {
1078 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1081 /* Setup internal state */
1082 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1084 /* Handle most of the hashes */
1085 while (hashes_count > 3) {
1094 /* Handle the last 3 hashes (all the case statements fall through) */
1095 switch (hashes_count) {
1096 case 3 : c += hashes [2];
1097 case 2 : b += hashes [1];
1098 case 1 : a += hashes [0];
1100 case 0: /* nothing left to add */
1104 free (hashes_start);
1105 /* Report the result */
1106 return c % MONO_IMT_SIZE;
1115 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1116 guint32 imt_slot = mono_method_get_imt_slot (method);
1117 MonoImtBuilderEntry *entry;
1119 if (slot_num >= 0 && imt_slot != slot_num) {
1120 /* we build just a single imt slot and this is not it */
1124 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1125 entry->key = method;
1126 entry->value.vtable_slot = vtable_slot;
1127 entry->next = imt_builder [imt_slot];
1128 if (imt_builder [imt_slot] != NULL) {
1129 entry->children = imt_builder [imt_slot]->children + 1;
1130 if (entry->children == 1) {
1131 mono_stats.imt_slots_with_collisions++;
1132 *imt_collisions_bitmap |= (1 << imt_slot);
1135 entry->children = 0;
1136 mono_stats.imt_used_slots++;
1138 imt_builder [imt_slot] = entry;
1141 char *method_name = mono_method_full_name (method, TRUE);
1142 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1143 method, method_name, imt_slot, vtable_slot, entry->children);
1144 g_free (method_name);
1151 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1153 MonoMethod *method = e->key;
1154 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1158 method->klass->name_space,
1159 method->klass->name,
1162 printf (" * %s: NULL\n", message);
1168 compare_imt_builder_entries (const void *p1, const void *p2) {
1169 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1170 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1172 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1176 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1178 int count = end - start;
1179 int chunk_start = out_array->len;
1182 for (i = start; i < end; ++i) {
1183 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1184 item->key = sorted_array [i]->key;
1185 item->value = sorted_array [i]->value;
1186 item->has_target_code = sorted_array [i]->has_target_code;
1187 item->is_equals = TRUE;
1189 item->check_target_idx = out_array->len + 1;
1191 item->check_target_idx = 0;
1192 g_ptr_array_add (out_array, item);
1195 int middle = start + count / 2;
1196 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1198 item->key = sorted_array [middle]->key;
1199 item->is_equals = FALSE;
1200 g_ptr_array_add (out_array, item);
1201 imt_emit_ir (sorted_array, start, middle, out_array);
1202 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1208 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1209 int number_of_entries = entries->children + 1;
1210 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1211 GPtrArray *result = g_ptr_array_new ();
1212 MonoImtBuilderEntry *current_entry;
1215 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1216 sorted_array [i] = current_entry;
1218 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1220 /*for (i = 0; i < number_of_entries; i++) {
1221 print_imt_entry (" sorted array:", sorted_array [i], i);
1224 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1226 free (sorted_array);
1231 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1233 if (imt_builder_entry != NULL) {
1234 if (imt_builder_entry->children == 0 && !fail_tramp) {
1235 /* No collision, return the vtable slot contents */
1236 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1238 /* Collision, build the thunk */
1239 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1242 result = imt_thunk_builder (vtable, domain,
1243 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1244 for (i = 0; i < imt_ir->len; ++i)
1245 g_free (g_ptr_array_index (imt_ir, i));
1246 g_ptr_array_free (imt_ir, TRUE);
1258 static MonoImtBuilderEntry*
1259 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1262 * LOCKING: requires the loader and domain locks.
1266 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1270 guint32 imt_collisions_bitmap = 0;
1271 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1272 int method_count = 0;
1273 gboolean record_method_count_for_max_collisions = FALSE;
1274 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1277 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1279 for (i = 0; i < klass->interface_offsets_count; ++i) {
1280 MonoClass *iface = klass->interfaces_packed [i];
1281 int interface_offset = klass->interface_offsets_packed [i];
1282 int method_slot_in_interface, vt_slot;
1284 if (mono_class_has_variant_generic_params (iface))
1285 has_variant_iface = TRUE;
1287 mono_class_setup_methods (iface);
1288 vt_slot = interface_offset;
1289 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1292 if (slot_num >= 0 && iface->is_inflated) {
1294 * The imt slot of the method is the same as for its declaring method,
1295 * see the comment in mono_method_get_imt_slot (), so we can
1296 * avoid inflating methods which will be discarded by
1297 * add_imt_builder_entry anyway.
1299 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1300 if (mono_method_get_imt_slot (method) != slot_num) {
1305 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1306 if (method->is_generic) {
1307 has_generic_virtual = TRUE;
1312 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1313 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1318 if (extra_interfaces) {
1319 int interface_offset = klass->vtable_size;
1321 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1322 MonoClass* iface = list_item->data;
1323 int method_slot_in_interface;
1324 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1325 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1327 if (method->is_generic)
1328 has_generic_virtual = TRUE;
1329 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1331 interface_offset += iface->method.count;
1334 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1335 /* overwrite the imt slot only if we're building all the entries or if
1336 * we're building this specific one
1338 if (slot_num < 0 || i == slot_num) {
1339 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1342 if (imt_builder [i]) {
1343 MonoImtBuilderEntry *entry;
1345 /* Link entries with imt_builder [i] */
1346 for (entry = entries; entry->next; entry = entry->next) {
1348 MonoMethod *method = (MonoMethod*)entry->key;
1349 char *method_name = mono_method_full_name (method, TRUE);
1350 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1351 g_free (method_name);
1354 entry->next = imt_builder [i];
1355 entries->children += imt_builder [i]->children + 1;
1357 imt_builder [i] = entries;
1360 if (has_generic_virtual || has_variant_iface) {
1362 * There might be collisions later when the the thunk is expanded.
1364 imt_collisions_bitmap |= (1 << i);
1367 * The IMT thunk might be called with an instance of one of the
1368 * generic virtual methods, so has to fallback to the IMT trampoline.
1370 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (i));
1372 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1375 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1379 if (imt_builder [i] != NULL) {
1380 int methods_in_slot = imt_builder [i]->children + 1;
1381 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1382 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1383 record_method_count_for_max_collisions = TRUE;
1385 method_count += methods_in_slot;
1389 mono_stats.imt_number_of_methods += method_count;
1390 if (record_method_count_for_max_collisions) {
1391 mono_stats.imt_method_count_when_max_collisions = method_count;
1394 for (i = 0; i < MONO_IMT_SIZE; i++) {
1395 MonoImtBuilderEntry* entry = imt_builder [i];
1396 while (entry != NULL) {
1397 MonoImtBuilderEntry* next = entry->next;
1403 /* we OR the bitmap since we may build just a single imt slot at a time */
1404 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1408 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1409 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1413 * mono_vtable_build_imt_slot:
1414 * @vtable: virtual object table struct
1415 * @imt_slot: slot in the IMT table
1417 * Fill the given @imt_slot in the IMT table of @vtable with
1418 * a trampoline or a thunk for the case of collisions.
1419 * This is part of the internal mono API.
1421 * LOCKING: Take the domain lock.
1424 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1426 gpointer *imt = (gpointer*)vtable;
1427 imt -= MONO_IMT_SIZE;
1428 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1430 /* no support for extra interfaces: the proxy objects will need
1431 * to build the complete IMT
1432 * Update and heck needs to ahppen inside the proper domain lock, as all
1433 * the changes made to a MonoVTable.
1435 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1436 mono_domain_lock (vtable->domain);
1437 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1438 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1439 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1440 mono_domain_unlock (vtable->domain);
1441 mono_loader_unlock ();
1446 * The first two free list entries both belong to the wait list: The
1447 * first entry is the pointer to the head of the list and the second
1448 * entry points to the last element. That way appending and removing
1449 * the first element are both O(1) operations.
1451 #ifdef MONO_SMALL_CONFIG
1452 #define NUM_FREE_LISTS 6
1454 #define NUM_FREE_LISTS 12
1456 #define FIRST_FREE_LIST_SIZE 64
1457 #define MAX_WAIT_LENGTH 50
1458 #define THUNK_THRESHOLD 10
1461 * LOCKING: The domain lock must be held.
1464 init_thunk_free_lists (MonoDomain *domain)
1466 if (domain->thunk_free_lists)
1468 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1472 list_index_for_size (int item_size)
1475 int size = FIRST_FREE_LIST_SIZE;
1477 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1486 * mono_method_alloc_generic_virtual_thunk:
1488 * @size: size in bytes
1490 * Allocs size bytes to be used for the code of a generic virtual
1491 * thunk. It's either allocated from the domain's code manager or
1492 * reused from a previously invalidated piece.
1494 * LOCKING: The domain lock must be held.
1497 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1499 static gboolean inited = FALSE;
1500 static int generic_virtual_thunks_size = 0;
1504 MonoThunkFreeList **l;
1506 init_thunk_free_lists (domain);
1508 size += sizeof (guint32);
1509 if (size < sizeof (MonoThunkFreeList))
1510 size = sizeof (MonoThunkFreeList);
1512 i = list_index_for_size (size);
1513 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1514 if ((*l)->size >= size) {
1515 MonoThunkFreeList *item = *l;
1517 return ((guint32*)item) + 1;
1521 /* no suitable item found - search lists of larger sizes */
1522 while (++i < NUM_FREE_LISTS) {
1523 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1526 g_assert (item->size > size);
1527 domain->thunk_free_lists [i] = item->next;
1528 return ((guint32*)item) + 1;
1531 /* still nothing found - allocate it */
1533 mono_counters_register ("Generic virtual thunk bytes",
1534 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1537 generic_virtual_thunks_size += size;
1539 p = mono_domain_code_reserve (domain, size);
1542 mono_domain_lock (domain);
1543 if (!domain->generic_virtual_thunks)
1544 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1545 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1546 mono_domain_unlock (domain);
1552 * LOCKING: The domain lock must be held.
1555 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1558 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1559 gboolean found = FALSE;
1561 mono_domain_lock (domain);
1562 if (!domain->generic_virtual_thunks)
1563 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1564 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1566 mono_domain_unlock (domain);
1569 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1571 init_thunk_free_lists (domain);
1573 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1574 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1575 int length = item->length;
1578 /* unlink the first item from the wait list */
1579 domain->thunk_free_lists [0] = item->next;
1580 domain->thunk_free_lists [0]->length = length - 1;
1582 i = list_index_for_size (item->size);
1584 /* put it in the free list */
1585 item->next = domain->thunk_free_lists [i];
1586 domain->thunk_free_lists [i] = item;
1590 if (domain->thunk_free_lists [1]) {
1591 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1592 domain->thunk_free_lists [0]->length++;
1594 g_assert (!domain->thunk_free_lists [0]);
1596 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1597 domain->thunk_free_lists [0]->length = 1;
1601 typedef struct _GenericVirtualCase {
1605 struct _GenericVirtualCase *next;
1606 } GenericVirtualCase;
1609 * get_generic_virtual_entries:
1611 * Return IMT entries for the generic virtual method instances and
1612 * variant interface methods for vtable slot
1615 static MonoImtBuilderEntry*
1616 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1618 GenericVirtualCase *list;
1619 MonoImtBuilderEntry *entries;
1621 mono_domain_lock (domain);
1622 if (!domain->generic_virtual_cases)
1623 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1625 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1628 for (; list; list = list->next) {
1629 MonoImtBuilderEntry *entry;
1631 if (list->count < THUNK_THRESHOLD)
1634 entry = g_new0 (MonoImtBuilderEntry, 1);
1635 entry->key = list->method;
1636 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1637 entry->has_target_code = 1;
1639 entry->children = entries->children + 1;
1640 entry->next = entries;
1644 mono_domain_unlock (domain);
1646 /* FIXME: Leaking memory ? */
1651 * mono_method_add_generic_virtual_invocation:
1653 * @vtable_slot: pointer to the vtable slot
1654 * @method: the inflated generic virtual method
1655 * @code: the method's code
1657 * Registers a call via unmanaged code to a generic virtual method
1658 * instantiation or variant interface method. If the number of calls reaches a threshold
1659 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1660 * virtual method thunk.
1663 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1664 gpointer *vtable_slot,
1665 MonoMethod *method, gpointer code)
1667 static gboolean inited = FALSE;
1668 static int num_added = 0;
1670 GenericVirtualCase *gvc, *list;
1671 MonoImtBuilderEntry *entries;
1675 mono_domain_lock (domain);
1676 if (!domain->generic_virtual_cases)
1677 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1679 /* Check whether the case was already added */
1680 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1683 if (gvc->method == method)
1688 /* If not found, make a new one */
1690 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1691 gvc->method = method;
1694 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1696 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1699 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1705 if (++gvc->count == THUNK_THRESHOLD) {
1706 gpointer *old_thunk = *vtable_slot;
1707 gpointer vtable_trampoline = NULL;
1708 gpointer imt_trampoline = NULL;
1710 if ((gpointer)vtable_slot < (gpointer)vtable) {
1711 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1712 int imt_slot = MONO_IMT_SIZE + displacement;
1714 /* Force the rebuild of the thunk at the next call */
1715 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1716 *vtable_slot = imt_trampoline;
1718 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1720 entries = get_generic_virtual_entries (domain, vtable_slot);
1722 sorted = imt_sort_slot_entries (entries);
1724 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1728 MonoImtBuilderEntry *next = entries->next;
1733 for (i = 0; i < sorted->len; ++i)
1734 g_free (g_ptr_array_index (sorted, i));
1735 g_ptr_array_free (sorted, TRUE);
1738 #ifndef __native_client__
1739 /* We don't re-use any thunks as there is a lot of overhead */
1740 /* to deleting and re-using code in Native Client. */
1741 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1742 invalidate_generic_virtual_thunk (domain, old_thunk);
1746 mono_domain_unlock (domain);
1749 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1752 * mono_class_vtable:
1753 * @domain: the application domain
1754 * @class: the class to initialize
1756 * VTables are domain specific because we create domain specific code, and
1757 * they contain the domain specific static class data.
1758 * On failure, NULL is returned, and class->exception_type is set.
1761 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1763 return mono_class_vtable_full (domain, class, FALSE);
1767 * mono_class_vtable_full:
1768 * @domain: the application domain
1769 * @class: the class to initialize
1770 * @raise_on_error if an exception should be raised on failure or not
1772 * VTables are domain specific because we create domain specific code, and
1773 * they contain the domain specific static class data.
1776 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1778 MonoClassRuntimeInfo *runtime_info;
1782 if (class->exception_type) {
1784 mono_raise_exception (mono_class_get_exception_for_failure (class));
1788 /* this check can be inlined in jitted code, too */
1789 runtime_info = class->runtime_info;
1790 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1791 return runtime_info->domain_vtables [domain->domain_id];
1792 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1796 * mono_class_try_get_vtable:
1797 * @domain: the application domain
1798 * @class: the class to initialize
1800 * This function tries to get the associated vtable from @class if
1801 * it was already created.
1804 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1806 MonoClassRuntimeInfo *runtime_info;
1810 runtime_info = class->runtime_info;
1811 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1812 return runtime_info->domain_vtables [domain->domain_id];
1817 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1819 size_t alloc_offset;
1822 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1823 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1824 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1826 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1827 g_assert ((imt_table_bytes & 7) == 4);
1834 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1838 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1841 MonoClassRuntimeInfo *runtime_info, *old_info;
1842 MonoClassField *field;
1844 int i, vtable_slots;
1845 size_t imt_table_bytes;
1847 guint32 vtable_size, class_size;
1849 gpointer *interface_offsets;
1851 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1852 mono_domain_lock (domain);
1853 runtime_info = class->runtime_info;
1854 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1855 mono_domain_unlock (domain);
1856 mono_loader_unlock ();
1857 return runtime_info->domain_vtables [domain->domain_id];
1859 if (!class->inited || class->exception_type) {
1860 if (!mono_class_init (class) || class->exception_type) {
1861 mono_domain_unlock (domain);
1862 mono_loader_unlock ();
1864 mono_raise_exception (mono_class_get_exception_for_failure (class));
1869 /* Array types require that their element type be valid*/
1870 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1871 MonoClass *element_class = class->element_class;
1872 if (!element_class->inited)
1873 mono_class_init (element_class);
1875 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1876 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1877 mono_class_setup_vtable (element_class);
1879 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1880 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1881 if (class->exception_type == MONO_EXCEPTION_NONE)
1882 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1883 mono_domain_unlock (domain);
1884 mono_loader_unlock ();
1886 mono_raise_exception (mono_class_get_exception_for_failure (class));
1892 * For some classes, mono_class_init () already computed class->vtable_size, and
1893 * that is all that is needed because of the vtable trampolines.
1895 if (!class->vtable_size)
1896 mono_class_setup_vtable (class);
1898 if (class->generic_class && !class->vtable)
1899 mono_class_check_vtable_constraints (class, NULL);
1901 /* Initialize klass->has_finalize */
1902 mono_class_has_finalizer (class);
1904 if (class->exception_type) {
1905 mono_domain_unlock (domain);
1906 mono_loader_unlock ();
1908 mono_raise_exception (mono_class_get_exception_for_failure (class));
1912 vtable_slots = class->vtable_size;
1913 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1914 class_size = mono_class_data_size (class);
1918 if (class->interface_offsets_count) {
1919 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1920 mono_stats.imt_number_of_tables++;
1921 mono_stats.imt_tables_size += imt_table_bytes;
1923 imt_table_bytes = 0;
1926 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1928 mono_stats.used_class_count++;
1929 mono_stats.class_vtable_size += vtable_size;
1931 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1932 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1933 g_assert (!((gsize)vt & 7));
1936 vt->rank = class->rank;
1937 vt->domain = domain;
1939 mono_class_compute_gc_descriptor (class);
1941 * We can't use typed allocation in the non-root domains, since the
1942 * collector needs the GC descriptor stored in the vtable even after
1943 * the mempool containing the vtable is destroyed when the domain is
1944 * unloaded. An alternative might be to allocate vtables in the GC
1945 * heap, but this does not seem to work (it leads to crashes inside
1946 * libgc). If that approach is tried, two gc descriptors need to be
1947 * allocated for each class: one for the root domain, and one for all
1948 * other domains. The second descriptor should contain a bit for the
1949 * vtable field in MonoObject, since we can no longer assume the
1950 * vtable is reachable by other roots after the appdomain is unloaded.
1952 #ifdef HAVE_BOEHM_GC
1953 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1954 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1957 vt->gc_descr = class->gc_descr;
1959 gc_bits = mono_gc_get_vtable_bits (class);
1960 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1962 vt->gc_bits = gc_bits;
1965 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1966 if (class->has_static_refs) {
1967 MonoGCDescriptor statics_gc_descr;
1969 gsize default_bitmap [4] = {0};
1972 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1973 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1974 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1975 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1976 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1977 if (bitmap != default_bitmap)
1980 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
1982 vt->has_static_fields = TRUE;
1983 mono_stats.class_static_data_size += class_size;
1987 while ((field = mono_class_get_fields (class, &iter))) {
1988 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1990 if (mono_field_is_deleted (field))
1992 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1993 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1994 if (special_static != SPECIAL_STATIC_NONE) {
1995 guint32 size, offset;
1997 gsize default_bitmap [4] = {0};
2002 if (mono_type_is_reference (field->type)) {
2003 default_bitmap [0] = 1;
2005 bitmap = default_bitmap;
2006 } else if (mono_type_is_struct (field->type)) {
2007 fclass = mono_class_from_mono_type (field->type);
2008 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2009 numbits = max_set + 1;
2011 default_bitmap [0] = 0;
2013 bitmap = default_bitmap;
2015 size = mono_type_size (field->type, &align);
2016 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2017 if (!domain->special_static_fields)
2018 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2019 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2020 if (bitmap != default_bitmap)
2023 * This marks the field as special static to speed up the
2024 * checks in mono_field_static_get/set_value ().
2030 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2031 MonoClass *fklass = mono_class_from_mono_type (field->type);
2032 const char *data = mono_field_get_data (field);
2034 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2035 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2036 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2039 if (fklass->valuetype) {
2040 memcpy (t, data, mono_class_value_size (fklass, NULL));
2042 /* it's a pointer type: add check */
2043 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2050 vt->max_interface_id = class->max_interface_id;
2051 vt->interface_bitmap = class->interface_bitmap;
2053 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2054 // class->name, class->interface_offsets_count);
2056 /* Initialize vtable */
2057 if (callbacks.get_vtable_trampoline) {
2058 // This also covers the AOT case
2059 for (i = 0; i < class->vtable_size; ++i) {
2060 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2063 mono_class_setup_vtable (class);
2065 for (i = 0; i < class->vtable_size; ++i) {
2068 if ((cm = class->vtable [i]))
2069 vt->vtable [i] = arch_create_jit_trampoline (cm);
2073 if (imt_table_bytes) {
2074 /* Now that the vtable is full, we can actually fill up the IMT */
2075 for (i = 0; i < MONO_IMT_SIZE; ++i)
2076 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2080 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2081 * re-acquire them and check if another thread has created the vtable in the meantime.
2083 /* Special case System.MonoType to avoid infinite recursion */
2084 if (class != mono_defaults.monotype_class) {
2085 /*FIXME check for OOM*/
2086 vt->type = mono_type_get_object (domain, &class->byval_arg);
2087 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2088 /* This is unregistered in
2089 unregister_vtable_reflection_type() in
2091 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2094 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2096 /* class_vtable_array keeps an array of created vtables
2098 g_ptr_array_add (domain->class_vtable_array, vt);
2099 /* class->runtime_info is protected by the loader lock, both when
2100 * it it enlarged and when it is stored info.
2104 * Store the vtable in class->runtime_info.
2105 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2107 mono_memory_barrier ();
2109 old_info = class->runtime_info;
2110 if (old_info && old_info->max_domain >= domain->domain_id) {
2111 /* someone already created a large enough runtime info */
2112 old_info->domain_vtables [domain->domain_id] = vt;
2114 int new_size = domain->domain_id;
2116 new_size = MAX (new_size, old_info->max_domain);
2118 /* make the new size a power of two */
2120 while (new_size > i)
2123 /* this is a bounded memory retention issue: may want to
2124 * handle it differently when we'll have a rcu-like system.
2126 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2127 runtime_info->max_domain = new_size - 1;
2128 /* copy the stuff from the older info */
2130 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2132 runtime_info->domain_vtables [domain->domain_id] = vt;
2134 mono_memory_barrier ();
2135 class->runtime_info = runtime_info;
2138 if (class == mono_defaults.monotype_class) {
2139 /*FIXME check for OOM*/
2140 vt->type = mono_type_get_object (domain, &class->byval_arg);
2141 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2142 /* This is unregistered in
2143 unregister_vtable_reflection_type() in
2145 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2148 mono_domain_unlock (domain);
2149 mono_loader_unlock ();
2151 /* make sure the parent is initialized */
2152 /*FIXME shouldn't this fail the current type?*/
2154 mono_class_vtable_full (domain, class->parent, raise_on_error);
2159 #ifndef DISABLE_REMOTING
2161 * mono_class_proxy_vtable:
2162 * @domain: the application domain
2163 * @remove_class: the remote class
2165 * Creates a vtable for transparent proxies. It is basically
2166 * a copy of the real vtable of the class wrapped in @remote_class,
2167 * but all function pointers invoke the remoting functions, and
2168 * vtable->klass points to the transparent proxy class, and not to @class.
2171 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2174 MonoVTable *vt, *pvt;
2175 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2177 GSList *extra_interfaces = NULL;
2178 MonoClass *class = remote_class->proxy_class;
2179 gpointer *interface_offsets;
2182 size_t imt_table_bytes;
2184 #ifdef COMPRESSED_INTERFACE_BITMAP
2188 vt = mono_class_vtable (domain, class);
2189 g_assert (vt); /*FIXME property handle failure*/
2190 max_interface_id = vt->max_interface_id;
2192 /* Calculate vtable space for extra interfaces */
2193 for (j = 0; j < remote_class->interface_count; j++) {
2194 MonoClass* iclass = remote_class->interfaces[j];
2198 /*FIXME test for interfaces with variant generic arguments*/
2199 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2200 continue; /* interface implemented by the class */
2201 if (g_slist_find (extra_interfaces, iclass))
2204 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2206 method_count = mono_class_num_methods (iclass);
2208 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2209 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2211 for (i = 0; i < ifaces->len; ++i) {
2212 MonoClass *ic = g_ptr_array_index (ifaces, i);
2213 /*FIXME test for interfaces with variant generic arguments*/
2214 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2215 continue; /* interface implemented by the class */
2216 if (g_slist_find (extra_interfaces, ic))
2218 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2219 method_count += mono_class_num_methods (ic);
2221 g_ptr_array_free (ifaces, TRUE);
2224 extra_interface_vtsize += method_count * sizeof (gpointer);
2225 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2228 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2229 mono_stats.imt_number_of_tables++;
2230 mono_stats.imt_tables_size += imt_table_bytes;
2232 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2234 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2236 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2237 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2238 g_assert (!((gsize)pvt & 7));
2240 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2242 pvt->klass = mono_defaults.transparent_proxy_class;
2243 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2244 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2246 /* initialize vtable */
2247 mono_class_setup_vtable (class);
2248 for (i = 0; i < class->vtable_size; ++i) {
2251 if ((cm = class->vtable [i]))
2252 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2254 pvt->vtable [i] = NULL;
2257 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2258 /* create trampolines for abstract methods */
2259 for (k = class; k; k = k->parent) {
2261 gpointer iter = NULL;
2262 while ((m = mono_class_get_methods (k, &iter)))
2263 if (!pvt->vtable [m->slot])
2264 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2268 pvt->max_interface_id = max_interface_id;
2269 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2270 #ifdef COMPRESSED_INTERFACE_BITMAP
2271 bitmap = g_malloc0 (bsize);
2273 bitmap = mono_domain_alloc0 (domain, bsize);
2276 for (i = 0; i < class->interface_offsets_count; ++i) {
2277 int interface_id = class->interfaces_packed [i]->interface_id;
2278 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2281 if (extra_interfaces) {
2282 int slot = class->vtable_size;
2288 /* Create trampolines for the methods of the interfaces */
2289 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2290 interf = list_item->data;
2292 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2296 while ((cm = mono_class_get_methods (interf, &iter)))
2297 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2299 slot += mono_class_num_methods (interf);
2303 /* Now that the vtable is full, we can actually fill up the IMT */
2304 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2305 if (extra_interfaces) {
2306 g_slist_free (extra_interfaces);
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2311 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2312 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2315 pvt->interface_bitmap = bitmap;
2320 #endif /* DISABLE_REMOTING */
2323 * mono_class_field_is_special_static:
2325 * Returns whether @field is a thread/context static field.
2328 mono_class_field_is_special_static (MonoClassField *field)
2330 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2332 if (mono_field_is_deleted (field))
2334 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2335 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2342 * mono_class_field_get_special_static_type:
2343 * @field: The MonoClassField describing the field.
2345 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2346 * SPECIAL_STATIC_NONE otherwise.
2349 mono_class_field_get_special_static_type (MonoClassField *field)
2351 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2352 return SPECIAL_STATIC_NONE;
2353 if (mono_field_is_deleted (field))
2354 return SPECIAL_STATIC_NONE;
2355 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2356 return field_is_special_static (field->parent, field);
2357 return SPECIAL_STATIC_NONE;
2361 * mono_class_has_special_static_fields:
2363 * Returns whenever @klass has any thread/context static fields.
2366 mono_class_has_special_static_fields (MonoClass *klass)
2368 MonoClassField *field;
2372 while ((field = mono_class_get_fields (klass, &iter))) {
2373 g_assert (field->parent == klass);
2374 if (mono_class_field_is_special_static (field))
2381 #ifndef DISABLE_REMOTING
2383 * create_remote_class_key:
2384 * Creates an array of pointers that can be used as a hash key for a remote class.
2385 * The first element of the array is the number of pointers.
2388 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2393 if (remote_class == NULL) {
2394 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2395 key = g_malloc (sizeof(gpointer) * 3);
2396 key [0] = GINT_TO_POINTER (2);
2397 key [1] = mono_defaults.marshalbyrefobject_class;
2398 key [2] = extra_class;
2400 key = g_malloc (sizeof(gpointer) * 2);
2401 key [0] = GINT_TO_POINTER (1);
2402 key [1] = extra_class;
2405 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2406 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2407 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2408 key [1] = remote_class->proxy_class;
2410 // Keep the list of interfaces sorted
2411 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2412 if (extra_class && remote_class->interfaces [i] > extra_class) {
2413 key [j++] = extra_class;
2416 key [j] = remote_class->interfaces [i];
2419 key [j] = extra_class;
2421 // Replace the old class. The interface list is the same
2422 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2423 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2424 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2425 for (i = 0; i < remote_class->interface_count; i++)
2426 key [2 + i] = remote_class->interfaces [i];
2434 * copy_remote_class_key:
2436 * Make a copy of KEY in the domain and return the copy.
2439 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2441 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2442 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2444 memcpy (mp_key, key, key_size);
2450 * mono_remote_class:
2451 * @domain: the application domain
2452 * @class_name: name of the remote class
2454 * Creates and initializes a MonoRemoteClass object for a remote type.
2456 * Can raise an exception on failure.
2459 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2462 MonoRemoteClass *rc;
2463 gpointer* key, *mp_key;
2466 key = create_remote_class_key (NULL, proxy_class);
2468 mono_domain_lock (domain);
2469 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2473 mono_domain_unlock (domain);
2477 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2478 if (!mono_error_ok (&error)) {
2480 mono_domain_unlock (domain);
2481 mono_error_raise_exception (&error);
2484 mp_key = copy_remote_class_key (domain, key);
2488 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2489 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2490 rc->interface_count = 1;
2491 rc->interfaces [0] = proxy_class;
2492 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2494 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2495 rc->interface_count = 0;
2496 rc->proxy_class = proxy_class;
2499 rc->default_vtable = NULL;
2500 rc->xdomain_vtable = NULL;
2501 rc->proxy_class_name = name;
2502 #ifndef DISABLE_PERFCOUNTERS
2503 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2506 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2508 mono_domain_unlock (domain);
2513 * clone_remote_class:
2514 * Creates a copy of the remote_class, adding the provided class or interface
2516 static MonoRemoteClass*
2517 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2519 MonoRemoteClass *rc;
2520 gpointer* key, *mp_key;
2522 key = create_remote_class_key (remote_class, extra_class);
2523 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2529 mp_key = copy_remote_class_key (domain, key);
2533 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2535 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2536 rc->proxy_class = remote_class->proxy_class;
2537 rc->interface_count = remote_class->interface_count + 1;
2539 // Keep the list of interfaces sorted, since the hash key of
2540 // the remote class depends on this
2541 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2542 if (remote_class->interfaces [i] > extra_class && i == j)
2543 rc->interfaces [j++] = extra_class;
2544 rc->interfaces [j] = remote_class->interfaces [i];
2547 rc->interfaces [j] = extra_class;
2549 // Replace the old class. The interface array is the same
2550 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2551 rc->proxy_class = extra_class;
2552 rc->interface_count = remote_class->interface_count;
2553 if (rc->interface_count > 0)
2554 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2557 rc->default_vtable = NULL;
2558 rc->xdomain_vtable = NULL;
2559 rc->proxy_class_name = remote_class->proxy_class_name;
2561 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2567 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2569 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2570 mono_domain_lock (domain);
2571 if (rp->target_domain_id != -1) {
2572 if (remote_class->xdomain_vtable == NULL)
2573 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2574 mono_domain_unlock (domain);
2575 mono_loader_unlock ();
2576 return remote_class->xdomain_vtable;
2578 if (remote_class->default_vtable == NULL) {
2581 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2582 klass = mono_class_from_mono_type (type);
2584 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2585 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2588 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2591 mono_domain_unlock (domain);
2592 mono_loader_unlock ();
2593 return remote_class->default_vtable;
2597 * mono_upgrade_remote_class:
2598 * @domain: the application domain
2599 * @tproxy: the proxy whose remote class has to be upgraded.
2600 * @klass: class to which the remote class can be casted.
2602 * Updates the vtable of the remote class by adding the necessary method slots
2603 * and interface offsets so it can be safely casted to klass. klass can be a
2604 * class or an interface.
2607 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2609 MonoTransparentProxy *tproxy;
2610 MonoRemoteClass *remote_class;
2611 gboolean redo_vtable;
2613 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2614 mono_domain_lock (domain);
2616 tproxy = (MonoTransparentProxy*) proxy_object;
2617 remote_class = tproxy->remote_class;
2619 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2622 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2623 if (remote_class->interfaces [i] == klass)
2624 redo_vtable = FALSE;
2627 redo_vtable = (remote_class->proxy_class != klass);
2631 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2632 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2635 mono_domain_unlock (domain);
2636 mono_loader_unlock ();
2638 #endif /* DISABLE_REMOTING */
2642 * mono_object_get_virtual_method:
2643 * @obj: object to operate on.
2646 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2647 * the instance of a callvirt of method.
2650 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2653 MonoMethod **vtable;
2654 gboolean is_proxy = FALSE;
2655 MonoMethod *res = NULL;
2657 klass = mono_object_class (obj);
2658 #ifndef DISABLE_REMOTING
2659 if (klass == mono_defaults.transparent_proxy_class) {
2660 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2665 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2668 mono_class_setup_vtable (klass);
2669 vtable = klass->vtable;
2671 if (method->slot == -1) {
2672 /* method->slot might not be set for instances of generic methods */
2673 if (method->is_inflated) {
2674 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2675 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2678 g_assert_not_reached ();
2682 /* check method->slot is a valid index: perform isinstance? */
2683 if (method->slot != -1) {
2684 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2686 gboolean variance_used = FALSE;
2687 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2688 g_assert (iface_offset > 0);
2689 res = vtable [iface_offset + method->slot];
2692 res = vtable [method->slot];
2696 #ifndef DISABLE_REMOTING
2698 /* It may be an interface, abstract class method or generic method */
2699 if (!res || mono_method_signature (res)->generic_param_count)
2702 /* generic methods demand invoke_with_check */
2703 if (mono_method_signature (res)->generic_param_count)
2704 res = mono_marshal_get_remoting_invoke_with_check (res);
2707 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2708 res = mono_cominterop_get_invoke (res);
2711 res = mono_marshal_get_remoting_invoke (res);
2716 if (method->is_inflated) {
2718 /* Have to inflate the result */
2719 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2720 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2730 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2732 g_error ("runtime invoke called on uninitialized runtime");
2736 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2739 * mono_runtime_invoke:
2740 * @method: method to invoke
2741 * @obJ: object instance
2742 * @params: arguments to the method
2743 * @exc: exception information.
2745 * Invokes the method represented by @method on the object @obj.
2747 * obj is the 'this' pointer, it should be NULL for static
2748 * methods, a MonoObject* for object instances and a pointer to
2749 * the value type for value types.
2751 * The params array contains the arguments to the method with the
2752 * same convention: MonoObject* pointers for object instances and
2753 * pointers to the value type otherwise.
2755 * From unmanaged code you'll usually use the
2756 * mono_runtime_invoke() variant.
2758 * Note that this function doesn't handle virtual methods for
2759 * you, it will exec the exact method you pass: we still need to
2760 * expose a function to lookup the derived class implementation
2761 * of a virtual method (there are examples of this in the code,
2764 * You can pass NULL as the exc argument if you don't want to
2765 * catch exceptions, otherwise, *exc will be set to the exception
2766 * thrown, if any. if an exception is thrown, you can't use the
2767 * MonoObject* result from the function.
2769 * If the method returns a value type, it is boxed in an object
2773 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2777 if (mono_runtime_get_no_exec ())
2778 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2780 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2781 mono_profiler_method_start_invoke (method);
2783 result = default_mono_runtime_invoke (method, obj, params, exc);
2785 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2786 mono_profiler_method_end_invoke (method);
2792 * mono_method_get_unmanaged_thunk:
2793 * @method: method to generate a thunk for.
2795 * Returns an unmanaged->managed thunk that can be used to call
2796 * a managed method directly from C.
2798 * The thunk's C signature closely matches the managed signature:
2800 * C#: public bool Equals (object obj);
2801 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2802 * MonoObject*, MonoException**);
2804 * The 1st ("this") parameter must not be used with static methods:
2806 * C#: public static bool ReferenceEquals (object a, object b);
2807 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2810 * The last argument must be a non-null pointer of a MonoException* pointer.
2811 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2812 * exception has been thrown in managed code. Otherwise it will point
2813 * to the MonoException* caught by the thunk. In this case, the result of
2814 * the thunk is undefined:
2816 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2817 * MonoException *ex = NULL;
2818 * Equals func = mono_method_get_unmanaged_thunk (method);
2819 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2821 * // handle exception
2824 * The calling convention of the thunk matches the platform's default
2825 * convention. This means that under Windows, C declarations must
2826 * contain the __stdcall attribute:
2828 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2829 * MonoObject*, MonoException**);
2833 * Value type arguments and return values are treated as they were objects:
2835 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2836 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2838 * Arguments must be properly boxed upon trunk's invocation, while return
2839 * values must be unboxed.
2842 mono_method_get_unmanaged_thunk (MonoMethod *method)
2844 method = mono_marshal_get_thunk_invoke_wrapper (method);
2845 return mono_compile_method (method);
2849 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2853 /* object fields cannot be byref, so we don't need a
2855 gpointer *p = (gpointer*)dest;
2862 case MONO_TYPE_BOOLEAN:
2864 case MONO_TYPE_U1: {
2865 guint8 *p = (guint8*)dest;
2866 *p = value ? *(guint8*)value : 0;
2871 case MONO_TYPE_CHAR: {
2872 guint16 *p = (guint16*)dest;
2873 *p = value ? *(guint16*)value : 0;
2876 #if SIZEOF_VOID_P == 4
2881 case MONO_TYPE_U4: {
2882 gint32 *p = (gint32*)dest;
2883 *p = value ? *(gint32*)value : 0;
2886 #if SIZEOF_VOID_P == 8
2891 case MONO_TYPE_U8: {
2892 gint64 *p = (gint64*)dest;
2893 *p = value ? *(gint64*)value : 0;
2896 case MONO_TYPE_R4: {
2897 float *p = (float*)dest;
2898 *p = value ? *(float*)value : 0;
2901 case MONO_TYPE_R8: {
2902 double *p = (double*)dest;
2903 *p = value ? *(double*)value : 0;
2906 case MONO_TYPE_STRING:
2907 case MONO_TYPE_SZARRAY:
2908 case MONO_TYPE_CLASS:
2909 case MONO_TYPE_OBJECT:
2910 case MONO_TYPE_ARRAY:
2911 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2913 case MONO_TYPE_FNPTR:
2914 case MONO_TYPE_PTR: {
2915 gpointer *p = (gpointer*)dest;
2916 *p = deref_pointer? *(gpointer*)value: value;
2919 case MONO_TYPE_VALUETYPE:
2920 /* note that 't' and 'type->type' can be different */
2921 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2922 t = mono_class_enum_basetype (type->data.klass)->type;
2925 MonoClass *class = mono_class_from_mono_type (type);
2926 int size = mono_class_value_size (class, NULL);
2928 mono_gc_bzero_atomic (dest, size);
2930 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2933 case MONO_TYPE_GENERICINST:
2934 t = type->data.generic_class->container_class->byval_arg.type;
2937 g_error ("got type %x", type->type);
2942 * mono_field_set_value:
2943 * @obj: Instance object
2944 * @field: MonoClassField describing the field to set
2945 * @value: The value to be set
2947 * Sets the value of the field described by @field in the object instance @obj
2948 * to the value passed in @value. This method should only be used for instance
2949 * fields. For static fields, use mono_field_static_set_value.
2951 * The value must be on the native format of the field type.
2954 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2958 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2960 dest = (char*)obj + field->offset;
2961 mono_copy_value (field->type, dest, value, FALSE);
2965 * mono_field_static_set_value:
2966 * @field: MonoClassField describing the field to set
2967 * @value: The value to be set
2969 * Sets the value of the static field described by @field
2970 * to the value passed in @value.
2972 * The value must be on the native format of the field type.
2975 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2979 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2980 /* you cant set a constant! */
2981 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2983 if (field->offset == -1) {
2984 /* Special static */
2987 mono_domain_lock (vt->domain);
2988 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2989 mono_domain_unlock (vt->domain);
2990 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2992 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2994 mono_copy_value (field->type, dest, value, FALSE);
2998 * mono_vtable_get_static_field_data:
3000 * Internal use function: return a pointer to the memory holding the static fields
3001 * for a class or NULL if there are no static fields.
3002 * This is exported only for use by the debugger.
3005 mono_vtable_get_static_field_data (MonoVTable *vt)
3007 if (!vt->has_static_fields)
3009 return vt->vtable [vt->klass->vtable_size];
3013 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3017 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3018 if (field->offset == -1) {
3019 /* Special static */
3022 mono_domain_lock (vt->domain);
3023 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3024 mono_domain_unlock (vt->domain);
3025 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3027 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3030 src = (guint8*)obj + field->offset;
3037 * mono_field_get_value:
3038 * @obj: Object instance
3039 * @field: MonoClassField describing the field to fetch information from
3040 * @value: pointer to the location where the value will be stored
3042 * Use this routine to get the value of the field @field in the object
3045 * The pointer provided by value must be of the field type, for reference
3046 * types this is a MonoObject*, for value types its the actual pointer to
3051 * mono_field_get_value (obj, int_field, &i);
3054 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3060 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3062 src = (char*)obj + field->offset;
3063 mono_copy_value (field->type, value, src, TRUE);
3067 * mono_field_get_value_object:
3068 * @domain: domain where the object will be created (if boxing)
3069 * @field: MonoClassField describing the field to fetch information from
3070 * @obj: The object instance for the field.
3072 * Returns: a new MonoObject with the value from the given field. If the
3073 * field represents a value type, the value is boxed.
3077 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3081 MonoVTable *vtable = NULL;
3083 gboolean is_static = FALSE;
3084 gboolean is_ref = FALSE;
3085 gboolean is_literal = FALSE;
3086 gboolean is_ptr = FALSE;
3088 MonoType *type = mono_field_get_type_checked (field, &error);
3090 if (!mono_error_ok (&error))
3091 mono_error_raise_exception (&error);
3093 switch (type->type) {
3094 case MONO_TYPE_STRING:
3095 case MONO_TYPE_OBJECT:
3096 case MONO_TYPE_CLASS:
3097 case MONO_TYPE_ARRAY:
3098 case MONO_TYPE_SZARRAY:
3103 case MONO_TYPE_BOOLEAN:
3106 case MONO_TYPE_CHAR:
3115 case MONO_TYPE_VALUETYPE:
3116 is_ref = type->byref;
3118 case MONO_TYPE_GENERICINST:
3119 is_ref = !mono_type_generic_inst_is_valuetype (type);
3125 g_error ("type 0x%x not handled in "
3126 "mono_field_get_value_object", type->type);
3130 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3133 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3137 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3138 if (!vtable->initialized)
3139 mono_runtime_class_init (vtable);
3147 get_default_field_value (domain, field, &o);
3148 } else if (is_static) {
3149 mono_field_static_get_value (vtable, field, &o);
3151 mono_field_get_value (obj, field, &o);
3157 static MonoMethod *m;
3163 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3164 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3170 get_default_field_value (domain, field, v);
3171 } else if (is_static) {
3172 mono_field_static_get_value (vtable, field, v);
3174 mono_field_get_value (obj, field, v);
3177 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3178 args [0] = ptr ? *ptr : NULL;
3179 args [1] = mono_type_get_object (mono_domain_get (), type);
3181 return mono_runtime_invoke (m, NULL, args, NULL);
3184 /* boxed value type */
3185 klass = mono_class_from_mono_type (type);
3187 if (mono_class_is_nullable (klass))
3188 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3190 o = mono_object_new (domain, klass);
3191 v = ((gchar *) o) + sizeof (MonoObject);
3194 get_default_field_value (domain, field, v);
3195 } else if (is_static) {
3196 mono_field_static_get_value (vtable, field, v);
3198 mono_field_get_value (obj, field, v);
3205 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3208 const char *p = blob;
3209 mono_metadata_decode_blob_size (p, &p);
3212 case MONO_TYPE_BOOLEAN:
3215 *(guint8 *) value = *p;
3217 case MONO_TYPE_CHAR:
3220 *(guint16*) value = read16 (p);
3224 *(guint32*) value = read32 (p);
3228 *(guint64*) value = read64 (p);
3231 readr4 (p, (float*) value);
3234 readr8 (p, (double*) value);
3236 case MONO_TYPE_STRING:
3237 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3239 case MONO_TYPE_CLASS:
3240 *(gpointer*) value = NULL;
3244 g_warning ("type 0x%02x should not be in constant table", type);
3250 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3252 MonoTypeEnum def_type;
3255 data = mono_class_get_field_default_value (field, &def_type);
3256 mono_get_constant_value_from_blob (domain, def_type, data, value);
3260 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3264 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3266 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3267 get_default_field_value (vt->domain, field, value);
3271 if (field->offset == -1) {
3272 /* Special static */
3273 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3274 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3276 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3278 mono_copy_value (field->type, value, src, TRUE);
3282 * mono_field_static_get_value:
3283 * @vt: vtable to the object
3284 * @field: MonoClassField describing the field to fetch information from
3285 * @value: where the value is returned
3287 * Use this routine to get the value of the static field @field value.
3289 * The pointer provided by value must be of the field type, for reference
3290 * types this is a MonoObject*, for value types its the actual pointer to
3295 * mono_field_static_get_value (vt, int_field, &i);
3298 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3300 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3304 * mono_property_set_value:
3305 * @prop: MonoProperty to set
3306 * @obj: instance object on which to act
3307 * @params: parameters to pass to the propery
3308 * @exc: optional exception
3310 * Invokes the property's set method with the given arguments on the
3311 * object instance obj (or NULL for static properties).
3313 * You can pass NULL as the exc argument if you don't want to
3314 * catch exceptions, otherwise, *exc will be set to the exception
3315 * thrown, if any. if an exception is thrown, you can't use the
3316 * MonoObject* result from the function.
3319 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3321 default_mono_runtime_invoke (prop->set, obj, params, exc);
3325 * mono_property_get_value:
3326 * @prop: MonoProperty to fetch
3327 * @obj: instance object on which to act
3328 * @params: parameters to pass to the propery
3329 * @exc: optional exception
3331 * Invokes the property's get method with the given arguments on the
3332 * object instance obj (or NULL for static properties).
3334 * You can pass NULL as the exc argument if you don't want to
3335 * catch exceptions, otherwise, *exc will be set to the exception
3336 * thrown, if any. if an exception is thrown, you can't use the
3337 * MonoObject* result from the function.
3339 * Returns: the value from invoking the get method on the property.
3342 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3344 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3348 * mono_nullable_init:
3349 * @buf: The nullable structure to initialize.
3350 * @value: the value to initialize from
3351 * @klass: the type for the object
3353 * Initialize the nullable structure pointed to by @buf from @value which
3354 * should be a boxed value type. The size of @buf should be able to hold
3355 * as much data as the @klass->instance_size (which is the number of bytes
3356 * that will be copies).
3358 * Since Nullables have variable structure, we can not define a C
3359 * structure for them.
3362 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3364 MonoClass *param_class = klass->cast_class;
3366 mono_class_setup_fields_locking (klass);
3367 g_assert (klass->fields_inited);
3369 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3370 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3372 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3374 if (param_class->has_references)
3375 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3377 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3379 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3384 * mono_nullable_box:
3385 * @buf: The buffer representing the data to be boxed
3386 * @klass: the type to box it as.
3388 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3392 mono_nullable_box (guint8 *buf, MonoClass *klass)
3394 MonoClass *param_class = klass->cast_class;
3396 mono_class_setup_fields_locking (klass);
3397 g_assert (klass->fields_inited);
3399 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3400 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3402 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3403 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3404 if (param_class->has_references)
3405 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3407 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3415 * mono_get_delegate_invoke:
3416 * @klass: The delegate class
3418 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3421 mono_get_delegate_invoke (MonoClass *klass)
3425 /* This is called at runtime, so avoid the slower search in metadata */
3426 mono_class_setup_methods (klass);
3427 if (klass->exception_type)
3429 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3434 * mono_get_delegate_begin_invoke:
3435 * @klass: The delegate class
3437 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3440 mono_get_delegate_begin_invoke (MonoClass *klass)
3444 /* This is called at runtime, so avoid the slower search in metadata */
3445 mono_class_setup_methods (klass);
3446 if (klass->exception_type)
3448 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3453 * mono_get_delegate_end_invoke:
3454 * @klass: The delegate class
3456 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3459 mono_get_delegate_end_invoke (MonoClass *klass)
3463 /* This is called at runtime, so avoid the slower search in metadata */
3464 mono_class_setup_methods (klass);
3465 if (klass->exception_type)
3467 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3472 * mono_runtime_delegate_invoke:
3473 * @delegate: pointer to a delegate object.
3474 * @params: parameters for the delegate.
3475 * @exc: Pointer to the exception result.
3477 * Invokes the delegate method @delegate with the parameters provided.
3479 * You can pass NULL as the exc argument if you don't want to
3480 * catch exceptions, otherwise, *exc will be set to the exception
3481 * thrown, if any. if an exception is thrown, you can't use the
3482 * MonoObject* result from the function.
3485 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3488 MonoClass *klass = delegate->vtable->klass;
3490 im = mono_get_delegate_invoke (klass);
3492 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3494 return mono_runtime_invoke (im, delegate, params, exc);
3497 static char **main_args = NULL;
3498 static int num_main_args = 0;
3501 * mono_runtime_get_main_args:
3503 * Returns: a MonoArray with the arguments passed to the main program
3506 mono_runtime_get_main_args (void)
3510 MonoDomain *domain = mono_domain_get ();
3512 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3514 for (i = 0; i < num_main_args; ++i)
3515 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3521 free_main_args (void)
3525 for (i = 0; i < num_main_args; ++i)
3526 g_free (main_args [i]);
3533 * mono_runtime_set_main_args:
3534 * @argc: number of arguments from the command line
3535 * @argv: array of strings from the command line
3537 * Set the command line arguments from an embedding application that doesn't otherwise call
3538 * mono_runtime_run_main ().
3541 mono_runtime_set_main_args (int argc, char* argv[])
3546 main_args = g_new0 (char*, argc);
3547 num_main_args = argc;
3549 for (i = 0; i < argc; ++i) {
3552 utf8_arg = mono_utf8_from_external (argv[i]);
3553 if (utf8_arg == NULL) {
3554 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3555 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3559 main_args [i] = utf8_arg;
3566 * mono_runtime_run_main:
3567 * @method: the method to start the application with (usually Main)
3568 * @argc: number of arguments from the command line
3569 * @argv: array of strings from the command line
3570 * @exc: excetption results
3572 * Execute a standard Main() method (argc/argv contains the
3573 * executable name). This method also sets the command line argument value
3574 * needed by System.Environment.
3579 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3583 MonoArray *args = NULL;
3584 MonoDomain *domain = mono_domain_get ();
3585 gchar *utf8_fullpath;
3586 MonoMethodSignature *sig;
3588 g_assert (method != NULL);
3590 mono_thread_set_main (mono_thread_current ());
3592 main_args = g_new0 (char*, argc);
3593 num_main_args = argc;
3595 if (!g_path_is_absolute (argv [0])) {
3596 gchar *basename = g_path_get_basename (argv [0]);
3597 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3601 utf8_fullpath = mono_utf8_from_external (fullpath);
3602 if(utf8_fullpath == NULL) {
3603 /* Printing the arg text will cause glib to
3604 * whinge about "Invalid UTF-8", but at least
3605 * its relevant, and shows the problem text
3608 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3609 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3616 utf8_fullpath = mono_utf8_from_external (argv[0]);
3617 if(utf8_fullpath == NULL) {
3618 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3619 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3624 main_args [0] = utf8_fullpath;
3626 for (i = 1; i < argc; ++i) {
3629 utf8_arg=mono_utf8_from_external (argv[i]);
3630 if(utf8_arg==NULL) {
3631 /* Ditto the comment about Invalid UTF-8 here */
3632 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3633 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3637 main_args [i] = utf8_arg;
3642 sig = mono_method_signature (method);
3644 g_print ("Unable to load Main method.\n");
3648 if (sig->param_count) {
3649 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3650 for (i = 0; i < argc; ++i) {
3651 /* The encodings should all work, given that
3652 * we've checked all these args for the
3655 gchar *str = mono_utf8_from_external (argv [i]);
3656 MonoString *arg = mono_string_new (domain, str);
3657 mono_array_setref (args, i, arg);
3661 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3664 mono_assembly_set_main (method->klass->image->assembly);
3666 return mono_runtime_exec_main (method, args, exc);
3670 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3672 static MonoMethod *serialize_method;
3677 if (!serialize_method) {
3678 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3679 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3682 if (!serialize_method) {
3687 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3691 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3699 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3701 static MonoMethod *deserialize_method;
3706 if (!deserialize_method) {
3707 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3708 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3710 if (!deserialize_method) {
3717 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3724 #ifndef DISABLE_REMOTING
3726 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3728 static MonoMethod *get_proxy_method;
3730 MonoDomain *domain = mono_domain_get ();
3731 MonoRealProxy *real_proxy;
3732 MonoReflectionType *reflection_type;
3733 MonoTransparentProxy *transparent_proxy;
3735 if (!get_proxy_method)
3736 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3738 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3740 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3741 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3743 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3744 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3747 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3751 return (MonoObject*) transparent_proxy;
3753 #endif /* DISABLE_REMOTING */
3756 * mono_object_xdomain_representation
3758 * @target_domain: a domain
3759 * @exc: pointer to a MonoObject*
3761 * Creates a representation of obj in the domain target_domain. This
3762 * is either a copy of obj arrived through via serialization and
3763 * deserialization or a proxy, depending on whether the object is
3764 * serializable or marshal by ref. obj must not be in target_domain.
3766 * If the object cannot be represented in target_domain, NULL is
3767 * returned and *exc is set to an appropriate exception.
3770 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3772 MonoObject *deserialized = NULL;
3773 gboolean failure = FALSE;
3777 #ifndef DISABLE_REMOTING
3778 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3779 deserialized = make_transparent_proxy (obj, &failure, exc);
3784 MonoDomain *domain = mono_domain_get ();
3785 MonoObject *serialized;
3787 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3788 serialized = serialize_object (obj, &failure, exc);
3789 mono_domain_set_internal_with_options (target_domain, FALSE);
3791 deserialized = deserialize_object (serialized, &failure, exc);
3792 if (domain != target_domain)
3793 mono_domain_set_internal_with_options (domain, FALSE);
3796 return deserialized;
3799 /* Used in call_unhandled_exception_delegate */
3801 create_unhandled_exception_eventargs (MonoObject *exc)
3805 MonoMethod *method = NULL;
3806 MonoBoolean is_terminating = TRUE;
3809 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3812 mono_class_init (klass);
3814 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3815 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3819 args [1] = &is_terminating;
3821 obj = mono_object_new (mono_domain_get (), klass);
3822 mono_runtime_invoke (method, obj, args, NULL);
3827 /* Used in mono_unhandled_exception */
3829 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3830 MonoObject *e = NULL;
3832 MonoDomain *current_domain = mono_domain_get ();
3834 if (domain != current_domain)
3835 mono_domain_set_internal_with_options (domain, FALSE);
3837 g_assert (domain == mono_object_domain (domain->domain));
3839 if (mono_object_domain (exc) != domain) {
3840 MonoObject *serialization_exc;
3842 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3844 if (serialization_exc) {
3846 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3849 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3850 "System.Runtime.Serialization", "SerializationException",
3851 "Could not serialize unhandled exception.");
3855 g_assert (mono_object_domain (exc) == domain);
3857 pa [0] = domain->domain;
3858 pa [1] = create_unhandled_exception_eventargs (exc);
3859 mono_runtime_delegate_invoke (delegate, pa, &e);
3861 if (domain != current_domain)
3862 mono_domain_set_internal_with_options (current_domain, FALSE);
3866 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3867 if (!mono_error_ok (&error)) {
3868 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3869 mono_error_cleanup (&error);
3871 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3877 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3880 * mono_runtime_unhandled_exception_policy_set:
3881 * @policy: the new policy
3883 * This is a VM internal routine.
3885 * Sets the runtime policy for handling unhandled exceptions.
3888 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3889 runtime_unhandled_exception_policy = policy;
3893 * mono_runtime_unhandled_exception_policy_get:
3895 * This is a VM internal routine.
3897 * Gets the runtime policy for handling unhandled exceptions.
3899 MonoRuntimeUnhandledExceptionPolicy
3900 mono_runtime_unhandled_exception_policy_get (void) {
3901 return runtime_unhandled_exception_policy;
3905 * mono_unhandled_exception:
3906 * @exc: exception thrown
3908 * This is a VM internal routine.
3910 * We call this function when we detect an unhandled exception
3911 * in the default domain.
3913 * It invokes the * UnhandledException event in AppDomain or prints
3914 * a warning to the console
3917 mono_unhandled_exception (MonoObject *exc)
3919 MonoDomain *current_domain = mono_domain_get ();
3920 MonoDomain *root_domain = mono_get_root_domain ();
3921 MonoClassField *field;
3922 MonoObject *current_appdomain_delegate;
3923 MonoObject *root_appdomain_delegate;
3925 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3926 "UnhandledException");
3929 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3930 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3931 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3932 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3933 if (current_domain != root_domain) {
3934 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3936 current_appdomain_delegate = NULL;
3939 /* set exitcode only if we will abort the process */
3940 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3942 mono_environment_exitcode_set (1);
3943 mono_print_unhandled_exception (exc);
3945 if (root_appdomain_delegate) {
3946 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3948 if (current_appdomain_delegate) {
3949 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3956 * mono_runtime_exec_managed_code:
3957 * @domain: Application domain
3958 * @main_func: function to invoke from the execution thread
3959 * @main_args: parameter to the main_func
3961 * Launch a new thread to execute a function
3963 * main_func is called back from the thread with main_args as the
3964 * parameter. The callback function is expected to start Main()
3965 * eventually. This function then waits for all managed threads to
3967 * It is not necesseray anymore to execute managed code in a subthread,
3968 * so this function should not be used anymore by default: just
3969 * execute the code and then call mono_thread_manage ().
3972 mono_runtime_exec_managed_code (MonoDomain *domain,
3973 MonoMainThreadFunc main_func,
3976 mono_thread_create (domain, main_func, main_args);
3978 mono_thread_manage ();
3982 * Execute a standard Main() method (args doesn't contain the
3986 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3991 MonoCustomAttrInfo* cinfo;
3992 gboolean has_stathread_attribute;
3993 MonoInternalThread* thread = mono_thread_internal_current ();
3999 domain = mono_object_domain (args);
4000 if (!domain->entry_assembly) {
4002 MonoAssembly *assembly;
4004 assembly = method->klass->image->assembly;
4005 domain->entry_assembly = assembly;
4006 /* Domains created from another domain already have application_base and configuration_file set */
4007 if (domain->setup->application_base == NULL) {
4008 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4011 if (domain->setup->configuration_file == NULL) {
4012 str = g_strconcat (assembly->image->name, ".config", NULL);
4013 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4015 mono_set_private_bin_path_from_config (domain);
4019 cinfo = mono_custom_attrs_from_method (method);
4021 static MonoClass *stathread_attribute = NULL;
4022 if (!stathread_attribute)
4023 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4024 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4026 mono_custom_attrs_free (cinfo);
4028 has_stathread_attribute = FALSE;
4030 if (has_stathread_attribute) {
4031 thread->apartment_state = ThreadApartmentState_STA;
4033 thread->apartment_state = ThreadApartmentState_MTA;
4035 mono_thread_init_apartment_state ();
4037 /* FIXME: check signature of method */
4038 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4040 res = mono_runtime_invoke (method, NULL, pa, exc);
4042 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4046 mono_environment_exitcode_set (rval);
4048 mono_runtime_invoke (method, NULL, pa, exc);
4052 /* If the return type of Main is void, only
4053 * set the exitcode if an exception was thrown
4054 * (we don't want to blow away an
4055 * explicitly-set exit code)
4058 mono_environment_exitcode_set (rval);
4066 * mono_install_runtime_invoke:
4067 * @func: Function to install
4069 * This is a VM internal routine
4072 mono_install_runtime_invoke (MonoInvokeFunc func)
4074 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4079 * mono_runtime_invoke_array:
4080 * @method: method to invoke
4081 * @obJ: object instance
4082 * @params: arguments to the method
4083 * @exc: exception information.
4085 * Invokes the method represented by @method on the object @obj.
4087 * obj is the 'this' pointer, it should be NULL for static
4088 * methods, a MonoObject* for object instances and a pointer to
4089 * the value type for value types.
4091 * The params array contains the arguments to the method with the
4092 * same convention: MonoObject* pointers for object instances and
4093 * pointers to the value type otherwise. The _invoke_array
4094 * variant takes a C# object[] as the params argument (MonoArray
4095 * *params): in this case the value types are boxed inside the
4096 * respective reference representation.
4098 * From unmanaged code you'll usually use the
4099 * mono_runtime_invoke() variant.
4101 * Note that this function doesn't handle virtual methods for
4102 * you, it will exec the exact method you pass: we still need to
4103 * expose a function to lookup the derived class implementation
4104 * of a virtual method (there are examples of this in the code,
4107 * You can pass NULL as the exc argument if you don't want to
4108 * catch exceptions, otherwise, *exc will be set to the exception
4109 * thrown, if any. if an exception is thrown, you can't use the
4110 * MonoObject* result from the function.
4112 * If the method returns a value type, it is boxed in an object
4116 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4119 MonoMethodSignature *sig = mono_method_signature (method);
4120 gpointer *pa = NULL;
4123 gboolean has_byref_nullables = FALSE;
4125 if (NULL != params) {
4126 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4127 for (i = 0; i < mono_array_length (params); i++) {
4128 MonoType *t = sig->params [i];
4134 case MONO_TYPE_BOOLEAN:
4137 case MONO_TYPE_CHAR:
4146 case MONO_TYPE_VALUETYPE:
4147 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4148 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4149 pa [i] = mono_array_get (params, MonoObject*, i);
4151 has_byref_nullables = TRUE;
4153 /* MS seems to create the objects if a null is passed in */
4154 if (!mono_array_get (params, MonoObject*, i))
4155 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4159 * We can't pass the unboxed vtype byref to the callee, since
4160 * that would mean the callee would be able to modify boxed
4161 * primitive types. So we (and MS) make a copy of the boxed
4162 * object, pass that to the callee, and replace the original
4163 * boxed object in the arg array with the copy.
4165 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4166 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4167 mono_array_setref (params, i, copy);
4170 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4173 case MONO_TYPE_STRING:
4174 case MONO_TYPE_OBJECT:
4175 case MONO_TYPE_CLASS:
4176 case MONO_TYPE_ARRAY:
4177 case MONO_TYPE_SZARRAY:
4179 pa [i] = mono_array_addr (params, MonoObject*, i);
4180 // FIXME: I need to check this code path
4182 pa [i] = mono_array_get (params, MonoObject*, i);
4184 case MONO_TYPE_GENERICINST:
4186 t = &t->data.generic_class->container_class->this_arg;
4188 t = &t->data.generic_class->container_class->byval_arg;
4190 case MONO_TYPE_PTR: {
4193 /* The argument should be an IntPtr */
4194 arg = mono_array_get (params, MonoObject*, i);
4198 g_assert (arg->vtable->klass == mono_defaults.int_class);
4199 pa [i] = ((MonoIntPtr*)arg)->m_value;
4204 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4209 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4212 if (mono_class_is_nullable (method->klass)) {
4213 /* Need to create a boxed vtype instead */
4219 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4223 obj = mono_object_new (mono_domain_get (), method->klass);
4224 g_assert (obj); /*maybe we should raise a TLE instead?*/
4225 #ifndef DISABLE_REMOTING
4226 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4227 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4230 if (method->klass->valuetype)
4231 o = mono_object_unbox (obj);
4234 } else if (method->klass->valuetype) {
4235 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4238 mono_runtime_invoke (method, o, pa, exc);
4241 if (mono_class_is_nullable (method->klass)) {
4242 MonoObject *nullable;
4244 /* Convert the unboxed vtype into a Nullable structure */
4245 nullable = mono_object_new (mono_domain_get (), method->klass);
4247 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4248 obj = mono_object_unbox (nullable);
4251 /* obj must be already unboxed if needed */
4252 res = mono_runtime_invoke (method, obj, pa, exc);
4254 if (sig->ret->type == MONO_TYPE_PTR) {
4255 MonoClass *pointer_class;
4256 static MonoMethod *box_method;
4258 MonoObject *box_exc;
4261 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4262 * convert it to a Pointer object.
4264 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4266 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4268 g_assert (res->vtable->klass == mono_defaults.int_class);
4269 box_args [0] = ((MonoIntPtr*)res)->m_value;
4270 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4271 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4272 g_assert (!box_exc);
4275 if (has_byref_nullables) {
4277 * The runtime invoke wrapper already converted byref nullables back,
4278 * and stored them in pa, we just need to copy them back to the
4281 for (i = 0; i < mono_array_length (params); i++) {
4282 MonoType *t = sig->params [i];
4284 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4285 mono_array_setref (params, i, pa [i]);
4294 arith_overflow (void)
4296 mono_raise_exception (mono_get_exception_overflow ());
4301 * @klass: the class of the object that we want to create
4303 * Returns: a newly created object whose definition is
4304 * looked up using @klass. This will not invoke any constructors,
4305 * so the consumer of this routine has to invoke any constructors on
4306 * its own to initialize the object.
4308 * It returns NULL on failure.
4311 mono_object_new (MonoDomain *domain, MonoClass *klass)
4315 vtable = mono_class_vtable (domain, klass);
4318 return mono_object_new_specific (vtable);
4322 * mono_object_new_pinned:
4324 * Same as mono_object_new, but the returned object will be pinned.
4325 * For SGEN, these objects will only be freed at appdomain unload.
4328 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4332 vtable = mono_class_vtable (domain, klass);
4337 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4339 return mono_object_new_specific (vtable);
4344 * mono_object_new_specific:
4345 * @vtable: the vtable of the object that we want to create
4347 * Returns: A newly created object with class and domain specified
4351 mono_object_new_specific (MonoVTable *vtable)
4355 /* check for is_com_object for COM Interop */
4356 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4359 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4362 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4365 mono_class_init (klass);
4367 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4369 vtable->domain->create_proxy_for_type_method = im;
4372 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4374 o = mono_runtime_invoke (im, NULL, pa, NULL);
4375 if (o != NULL) return o;
4378 return mono_object_new_alloc_specific (vtable);
4382 mono_object_new_alloc_specific (MonoVTable *vtable)
4384 MonoObject *o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4386 if (G_UNLIKELY (vtable->klass->has_finalize))
4387 mono_object_register_finalizer (o);
4393 mono_object_new_fast (MonoVTable *vtable)
4395 return mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4399 * mono_class_get_allocation_ftn:
4401 * @for_box: the object will be used for boxing
4402 * @pass_size_in_words:
4404 * Return the allocation function appropriate for the given class.
4408 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4410 *pass_size_in_words = FALSE;
4412 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4413 return mono_object_new_specific;
4415 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4417 return mono_object_new_fast;
4420 * FIXME: This is actually slower than mono_object_new_fast, because
4421 * of the overhead of parameter passing.
4424 *pass_size_in_words = TRUE;
4425 #ifdef GC_REDIRECT_TO_LOCAL
4426 return GC_local_gcj_fast_malloc;
4428 return GC_gcj_fast_malloc;
4433 return mono_object_new_specific;
4437 * mono_object_new_from_token:
4438 * @image: Context where the type_token is hosted
4439 * @token: a token of the type that we want to create
4441 * Returns: A newly created object whose definition is
4442 * looked up using @token in the @image image
4445 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4450 class = mono_class_get_checked (image, token, &error);
4451 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4453 return mono_object_new (domain, class);
4458 * mono_object_clone:
4459 * @obj: the object to clone
4461 * Returns: A newly created object who is a shallow copy of @obj
4464 mono_object_clone (MonoObject *obj)
4467 int size = obj->vtable->klass->instance_size;
4469 if (obj->vtable->klass->rank)
4470 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4472 o = mono_gc_alloc_obj (obj->vtable, size);
4474 /* If the object doesn't contain references this will do a simple memmove. */
4475 mono_gc_wbarrier_object_copy (o, obj);
4477 if (obj->vtable->klass->has_finalize)
4478 mono_object_register_finalizer (o);
4483 * mono_array_full_copy:
4484 * @src: source array to copy
4485 * @dest: destination array
4487 * Copies the content of one array to another with exactly the same type and size.
4490 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4493 MonoClass *klass = src->obj.vtable->klass;
4495 g_assert (klass == dest->obj.vtable->klass);
4497 size = mono_array_length (src);
4498 g_assert (size == mono_array_length (dest));
4499 size *= mono_array_element_size (klass);
4501 if (klass->element_class->valuetype) {
4502 if (klass->element_class->has_references)
4503 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4505 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4507 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4510 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4515 * mono_array_clone_in_domain:
4516 * @domain: the domain in which the array will be cloned into
4517 * @array: the array to clone
4519 * This routine returns a copy of the array that is hosted on the
4520 * specified MonoDomain.
4523 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4528 MonoClass *klass = array->obj.vtable->klass;
4530 if (array->bounds == NULL) {
4531 size = mono_array_length (array);
4532 o = mono_array_new_full (domain, klass, &size, NULL);
4534 size *= mono_array_element_size (klass);
4536 if (klass->element_class->valuetype) {
4537 if (klass->element_class->has_references)
4538 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4540 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4542 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4545 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4550 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4551 size = mono_array_element_size (klass);
4552 for (i = 0; i < klass->rank; ++i) {
4553 sizes [i] = array->bounds [i].length;
4554 size *= array->bounds [i].length;
4555 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4557 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4559 if (klass->element_class->valuetype) {
4560 if (klass->element_class->has_references)
4561 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4563 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4565 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4568 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4576 * @array: the array to clone
4578 * Returns: A newly created array who is a shallow copy of @array
4581 mono_array_clone (MonoArray *array)
4583 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4586 /* helper macros to check for overflow when calculating the size of arrays */
4587 #ifdef MONO_BIG_ARRAYS
4588 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4589 #define MYGUINT_MAX MYGUINT64_MAX
4590 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4591 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4592 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4593 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4594 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4596 #define MYGUINT32_MAX 4294967295U
4597 #define MYGUINT_MAX MYGUINT32_MAX
4598 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4599 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4600 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4601 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4602 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4606 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4610 byte_len = mono_array_element_size (class);
4611 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4614 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4616 byte_len += sizeof (MonoArray);
4624 * mono_array_new_full:
4625 * @domain: domain where the object is created
4626 * @array_class: array class
4627 * @lengths: lengths for each dimension in the array
4628 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4630 * This routine creates a new array objects with the given dimensions,
4631 * lower bounds and type.
4634 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4636 uintptr_t byte_len = 0, len, bounds_size;
4639 MonoArrayBounds *bounds;
4643 if (!array_class->inited)
4644 mono_class_init (array_class);
4648 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4649 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4651 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4655 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4657 for (i = 0; i < array_class->rank; ++i) {
4658 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4660 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4661 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4666 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4667 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4671 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4672 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4673 byte_len = (byte_len + 3) & ~3;
4674 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4675 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4676 byte_len += bounds_size;
4679 * Following three lines almost taken from mono_object_new ():
4680 * they need to be kept in sync.
4682 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4684 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4686 o = mono_gc_alloc_vector (vtable, byte_len, len);
4687 array = (MonoArray*)o;
4689 bounds = array->bounds;
4692 for (i = 0; i < array_class->rank; ++i) {
4693 bounds [i].length = lengths [i];
4695 bounds [i].lower_bound = lower_bounds [i];
4704 * @domain: domain where the object is created
4705 * @eclass: element class
4706 * @n: number of array elements
4708 * This routine creates a new szarray with @n elements of type @eclass.
4711 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4715 ac = mono_array_class_get (eclass, 1);
4718 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4722 * mono_array_new_specific:
4723 * @vtable: a vtable in the appropriate domain for an initialized class
4724 * @n: number of array elements
4726 * This routine is a fast alternative to mono_array_new() for code which
4727 * can be sure about the domain it operates in.
4730 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4736 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4741 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4742 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4745 o = mono_gc_alloc_vector (vtable, byte_len, n);
4752 * mono_string_new_utf16:
4753 * @text: a pointer to an utf16 string
4754 * @len: the length of the string
4756 * Returns: A newly created string object which contains @text.
4759 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4763 s = mono_string_new_size (domain, len);
4764 g_assert (s != NULL);
4766 memcpy (mono_string_chars (s), text, len * 2);
4772 * mono_string_new_utf32:
4773 * @text: a pointer to an utf32 string
4774 * @len: the length of the string
4776 * Returns: A newly created string object which contains @text.
4779 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4782 mono_unichar2 *utf16_output = NULL;
4783 gint32 utf16_len = 0;
4784 GError *error = NULL;
4785 glong items_written;
4787 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
4790 g_error_free (error);
4792 while (utf16_output [utf16_len]) utf16_len++;
4794 s = mono_string_new_size (domain, utf16_len);
4795 g_assert (s != NULL);
4797 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
4799 g_free (utf16_output);
4805 * mono_string_new_size:
4806 * @text: a pointer to an utf16 string
4807 * @len: the length of the string
4809 * Returns: A newly created string object of @len
4812 mono_string_new_size (MonoDomain *domain, gint32 len)
4818 /* check for overflow */
4819 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
4820 mono_gc_out_of_memory (-1);
4822 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
4823 g_assert (size > 0);
4825 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4828 s = mono_gc_alloc_string (vtable, size, len);
4834 * mono_string_new_len:
4835 * @text: a pointer to an utf8 string
4836 * @length: number of bytes in @text to consider
4838 * Returns: A newly created string object which contains @text.
4841 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4843 GError *error = NULL;
4844 MonoString *o = NULL;
4846 glong items_written;
4848 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
4851 o = mono_string_new_utf16 (domain, ut, items_written);
4853 g_error_free (error);
4862 * @text: a pointer to an utf8 string
4864 * Returns: A newly created string object which contains @text.
4867 mono_string_new (MonoDomain *domain, const char *text)
4869 GError *error = NULL;
4870 MonoString *o = NULL;
4872 glong items_written;
4877 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4880 o = mono_string_new_utf16 (domain, ut, items_written);
4882 g_error_free (error);
4885 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4890 MonoString *o = NULL;
4892 if (!g_utf8_validate (text, -1, &end))
4895 len = g_utf8_strlen (text, -1);
4896 o = mono_string_new_size (domain, len);
4897 str = mono_string_chars (o);
4899 while (text < end) {
4900 *str++ = g_utf8_get_char (text);
4901 text = g_utf8_next_char (text);
4908 * mono_string_new_wrapper:
4909 * @text: pointer to utf8 characters.
4911 * Helper function to create a string object from @text in the current domain.
4914 mono_string_new_wrapper (const char *text)
4916 MonoDomain *domain = mono_domain_get ();
4919 return mono_string_new (domain, text);
4926 * @class: the class of the value
4927 * @value: a pointer to the unboxed data
4929 * Returns: A newly created object which contains @value.
4932 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4938 g_assert (class->valuetype);
4939 if (mono_class_is_nullable (class))
4940 return mono_nullable_box (value, class);
4942 vtable = mono_class_vtable (domain, class);
4945 size = mono_class_instance_size (class);
4946 res = mono_object_new_alloc_specific (vtable);
4948 size = size - sizeof (MonoObject);
4951 g_assert (size == mono_class_value_size (class, NULL));
4952 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4954 #if NO_UNALIGNED_ACCESS
4955 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
4959 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4962 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4965 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4968 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4971 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
4975 if (class->has_finalize)
4976 mono_object_register_finalizer (res);
4982 * @dest: destination pointer
4983 * @src: source pointer
4984 * @klass: a valuetype class
4986 * Copy a valuetype from @src to @dest. This function must be used
4987 * when @klass contains references fields.
4990 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4992 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4996 * mono_value_copy_array:
4997 * @dest: destination array
4998 * @dest_idx: index in the @dest array
4999 * @src: source pointer
5000 * @count: number of items
5002 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5003 * This function must be used when @klass contains references fields.
5004 * Overlap is handled.
5007 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5009 int size = mono_array_element_size (dest->obj.vtable->klass);
5010 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5011 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5012 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5016 * mono_object_get_domain:
5017 * @obj: object to query
5019 * Returns: the MonoDomain where the object is hosted
5022 mono_object_get_domain (MonoObject *obj)
5024 return mono_object_domain (obj);
5028 * mono_object_get_class:
5029 * @obj: object to query
5031 * Returns: the MonOClass of the object.
5034 mono_object_get_class (MonoObject *obj)
5036 return mono_object_class (obj);
5039 * mono_object_get_size:
5040 * @o: object to query
5042 * Returns: the size, in bytes, of @o
5045 mono_object_get_size (MonoObject* o)
5047 MonoClass* klass = mono_object_class (o);
5048 if (klass == mono_defaults.string_class) {
5049 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5050 } else if (o->vtable->rank) {
5051 MonoArray *array = (MonoArray*)o;
5052 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5053 if (array->bounds) {
5056 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5060 return mono_class_instance_size (klass);
5065 * mono_object_unbox:
5066 * @obj: object to unbox
5068 * Returns: a pointer to the start of the valuetype boxed in this
5071 * This method will assert if the object passed is not a valuetype.
5074 mono_object_unbox (MonoObject *obj)
5076 /* add assert for valuetypes? */
5077 g_assert (obj->vtable->klass->valuetype);
5078 return ((char*)obj) + sizeof (MonoObject);
5082 * mono_object_isinst:
5084 * @klass: a pointer to a class
5086 * Returns: @obj if @obj is derived from @klass
5089 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5092 mono_class_init (klass);
5094 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5095 return mono_object_isinst_mbyref (obj, klass);
5100 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5104 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5113 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5114 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5118 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5119 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5122 MonoClass *oklass = vt->klass;
5123 if (mono_class_is_transparent_proxy (oklass))
5124 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5126 mono_class_setup_supertypes (klass);
5127 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5130 #ifndef DISABLE_REMOTING
5131 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5133 MonoDomain *domain = mono_domain_get ();
5135 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5136 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5137 MonoMethod *im = NULL;
5140 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5141 im = mono_object_get_virtual_method (rp, im);
5144 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5147 res = mono_runtime_invoke (im, rp, pa, NULL);
5149 if (*(MonoBoolean *) mono_object_unbox(res)) {
5150 /* Update the vtable of the remote type, so it can safely cast to this new type */
5151 mono_upgrade_remote_class (domain, obj, klass);
5155 #endif /* DISABLE_REMOTING */
5160 * mono_object_castclass_mbyref:
5162 * @klass: a pointer to a class
5164 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5167 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5169 if (!obj) return NULL;
5170 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5172 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5174 "InvalidCastException"));
5179 MonoDomain *orig_domain;
5185 str_lookup (MonoDomain *domain, gpointer user_data)
5187 LDStrInfo *info = user_data;
5188 if (info->res || domain == info->orig_domain)
5190 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5196 mono_string_get_pinned (MonoString *str)
5200 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5201 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5203 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5204 news->length = mono_string_length (str);
5210 #define mono_string_get_pinned(str) (str)
5214 mono_string_is_interned_lookup (MonoString *str, int insert)
5216 MonoGHashTable *ldstr_table;
5217 MonoString *s, *res;
5220 domain = ((MonoObject *)str)->vtable->domain;
5221 ldstr_table = domain->ldstr_table;
5223 res = mono_g_hash_table_lookup (ldstr_table, str);
5229 /* Allocate outside the lock */
5231 s = mono_string_get_pinned (str);
5234 res = mono_g_hash_table_lookup (ldstr_table, str);
5239 mono_g_hash_table_insert (ldstr_table, s, s);
5244 LDStrInfo ldstr_info;
5245 ldstr_info.orig_domain = domain;
5246 ldstr_info.ins = str;
5247 ldstr_info.res = NULL;
5249 mono_domain_foreach (str_lookup, &ldstr_info);
5250 if (ldstr_info.res) {
5252 * the string was already interned in some other domain:
5253 * intern it in the current one as well.
5255 mono_g_hash_table_insert (ldstr_table, str, str);
5265 * mono_string_is_interned:
5266 * @o: String to probe
5268 * Returns whether the string has been interned.
5271 mono_string_is_interned (MonoString *o)
5273 return mono_string_is_interned_lookup (o, FALSE);
5277 * mono_string_intern:
5278 * @o: String to intern
5280 * Interns the string passed.
5281 * Returns: The interned string.
5284 mono_string_intern (MonoString *str)
5286 return mono_string_is_interned_lookup (str, TRUE);
5291 * @domain: the domain where the string will be used.
5292 * @image: a metadata context
5293 * @idx: index into the user string table.
5295 * Implementation for the ldstr opcode.
5296 * Returns: a loaded string from the @image/@idx combination.
5299 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5301 if (image->dynamic) {
5302 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5305 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5306 return NULL; /*FIXME we should probably be raising an exception here*/
5307 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5312 * mono_ldstr_metadata_sig
5313 * @domain: the domain for the string
5314 * @sig: the signature of a metadata string
5316 * Returns: a MonoString for a string stored in the metadata
5319 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5321 const char *str = sig;
5322 MonoString *o, *interned;
5325 len2 = mono_metadata_decode_blob_size (str, &str);
5328 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5329 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5332 guint16 *p2 = (guint16*)mono_string_chars (o);
5333 for (i = 0; i < len2; ++i) {
5334 *p2 = GUINT16_FROM_LE (*p2);
5340 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5343 return interned; /* o will get garbage collected */
5345 o = mono_string_get_pinned (o);
5348 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5350 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5360 * mono_string_to_utf8:
5361 * @s: a System.String
5363 * Returns the UTF8 representation for @s.
5364 * The resulting buffer needs to be freed with mono_free().
5366 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5369 mono_string_to_utf8 (MonoString *s)
5372 char *result = mono_string_to_utf8_checked (s, &error);
5374 if (!mono_error_ok (&error))
5375 mono_error_raise_exception (&error);
5380 * mono_string_to_utf8_checked:
5381 * @s: a System.String
5382 * @error: a MonoError.
5384 * Converts a MonoString to its UTF8 representation. May fail; check
5385 * @error to determine whether the conversion was successful.
5386 * The resulting buffer should be freed with mono_free().
5389 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5393 GError *gerror = NULL;
5395 mono_error_init (error);
5401 return g_strdup ("");
5403 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5405 mono_error_set_argument (error, "string", "%s", gerror->message);
5406 g_error_free (gerror);
5409 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5410 if (s->length > written) {
5411 /* allocate the total length and copy the part of the string that has been converted */
5412 char *as2 = g_malloc0 (s->length);
5413 memcpy (as2, as, written);
5422 * mono_string_to_utf8_ignore:
5425 * Converts a MonoString to its UTF8 representation. Will ignore
5426 * invalid surrogate pairs.
5427 * The resulting buffer should be freed with mono_free().
5431 mono_string_to_utf8_ignore (MonoString *s)
5440 return g_strdup ("");
5442 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5444 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5445 if (s->length > written) {
5446 /* allocate the total length and copy the part of the string that has been converted */
5447 char *as2 = g_malloc0 (s->length);
5448 memcpy (as2, as, written);
5457 * mono_string_to_utf8_image_ignore:
5458 * @s: a System.String
5460 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5463 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5465 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5469 * mono_string_to_utf8_mp_ignore:
5470 * @s: a System.String
5472 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5475 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5477 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5482 * mono_string_to_utf16:
5485 * Return an null-terminated array of the utf-16 chars
5486 * contained in @s. The result must be freed with g_free().
5487 * This is a temporary helper until our string implementation
5488 * is reworked to always include the null terminating char.
5491 mono_string_to_utf16 (MonoString *s)
5498 as = g_malloc ((s->length * 2) + 2);
5499 as [(s->length * 2)] = '\0';
5500 as [(s->length * 2) + 1] = '\0';
5503 return (gunichar2 *)(as);
5506 memcpy (as, mono_string_chars(s), s->length * 2);
5507 return (gunichar2 *)(as);
5511 * mono_string_to_utf32:
5514 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5515 * contained in @s. The result must be freed with g_free().
5518 mono_string_to_utf32 (MonoString *s)
5520 mono_unichar4 *utf32_output = NULL;
5521 GError *error = NULL;
5522 glong items_written;
5527 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5530 g_error_free (error);
5532 return utf32_output;
5536 * mono_string_from_utf16:
5537 * @data: the UTF16 string (LPWSTR) to convert
5539 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5541 * Returns: a MonoString.
5544 mono_string_from_utf16 (gunichar2 *data)
5546 MonoDomain *domain = mono_domain_get ();
5552 while (data [len]) len++;
5554 return mono_string_new_utf16 (domain, data, len);
5558 * mono_string_from_utf32:
5559 * @data: the UTF32 string (LPWSTR) to convert
5561 * Converts a UTF32 (UCS-4)to a MonoString.
5563 * Returns: a MonoString.
5566 mono_string_from_utf32 (mono_unichar4 *data)
5568 MonoString* result = NULL;
5569 mono_unichar2 *utf16_output = NULL;
5570 GError *error = NULL;
5571 glong items_written;
5577 while (data [len]) len++;
5579 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5582 g_error_free (error);
5584 result = mono_string_from_utf16 (utf16_output);
5585 g_free (utf16_output);
5590 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5597 r = mono_string_to_utf8_ignore (s);
5599 r = mono_string_to_utf8_checked (s, error);
5600 if (!mono_error_ok (error))
5607 len = strlen (r) + 1;
5609 mp_s = mono_mempool_alloc (mp, len);
5611 mp_s = mono_image_alloc (image, len);
5613 memcpy (mp_s, r, len);
5621 * mono_string_to_utf8_image:
5622 * @s: a System.String
5624 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5627 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5629 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5633 * mono_string_to_utf8_mp:
5634 * @s: a System.String
5636 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5639 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5641 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5645 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5648 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5650 eh_callbacks = *cbs;
5653 MonoRuntimeExceptionHandlingCallbacks *
5654 mono_get_eh_callbacks (void)
5656 return &eh_callbacks;
5660 * mono_raise_exception:
5661 * @ex: exception object
5663 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5666 mono_raise_exception (MonoException *ex)
5669 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5670 * that will cause gcc to omit the function epilog, causing problems when
5671 * the JIT tries to walk the stack, since the return address on the stack
5672 * will point into the next function in the executable, not this one.
5674 eh_callbacks.mono_raise_exception (ex);
5678 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5680 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5684 * mono_wait_handle_new:
5685 * @domain: Domain where the object will be created
5686 * @handle: Handle for the wait handle
5688 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5691 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5693 MonoWaitHandle *res;
5694 gpointer params [1];
5695 static MonoMethod *handle_set;
5697 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5699 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5701 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5703 params [0] = &handle;
5704 mono_runtime_invoke (handle_set, res, params, NULL);
5710 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5712 static MonoClassField *f_os_handle;
5713 static MonoClassField *f_safe_handle;
5715 if (!f_os_handle && !f_safe_handle) {
5716 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5717 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5722 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5726 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5733 mono_runtime_capture_context (MonoDomain *domain)
5735 RuntimeInvokeFunction runtime_invoke;
5737 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5738 MonoMethod *method = mono_get_context_capture_method ();
5739 MonoMethod *wrapper;
5742 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5743 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5744 domain->capture_context_method = mono_compile_method (method);
5747 runtime_invoke = domain->capture_context_runtime_invoke;
5749 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5752 * mono_async_result_new:
5753 * @domain:domain where the object will be created.
5754 * @handle: wait handle.
5755 * @state: state to pass to AsyncResult
5756 * @data: C closure data.
5758 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5759 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5763 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5765 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5766 MonoObject *context = mono_runtime_capture_context (domain);
5767 /* we must capture the execution context from the original thread */
5769 MONO_OBJECT_SETREF (res, execution_context, context);
5770 /* note: result may be null if the flow is suppressed */
5774 MONO_OBJECT_SETREF (res, object_data, object_data);
5775 MONO_OBJECT_SETREF (res, async_state, state);
5777 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5779 res->sync_completed = FALSE;
5780 res->completed = FALSE;
5786 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
5792 g_assert (ares->async_delegate);
5794 ac = (MonoAsyncCall*) ares->object_data;
5796 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
5798 gpointer wait_event = NULL;
5800 ac->msg->exc = NULL;
5801 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
5802 MONO_OBJECT_SETREF (ac, res, res);
5804 mono_monitor_enter ((MonoObject*) ares);
5805 ares->completed = 1;
5807 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
5808 mono_monitor_exit ((MonoObject*) ares);
5810 if (wait_event != NULL)
5811 SetEvent (wait_event);
5813 if (ac->cb_method) {
5814 /* we swallow the excepton as it is the behavior on .NET */
5815 MonoObject *exc = NULL;
5816 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
5818 mono_unhandled_exception (exc);
5826 mono_message_init (MonoDomain *domain,
5827 MonoMethodMessage *this_obj,
5828 MonoReflectionMethod *method,
5829 MonoArray *out_args)
5831 static MonoClass *object_array_klass;
5832 static MonoClass *byte_array_klass;
5833 static MonoClass *string_array_klass;
5834 MonoMethodSignature *sig = mono_method_signature (method->method);
5840 if (!object_array_klass) {
5843 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5845 byte_array_klass = klass;
5847 klass = mono_array_class_get (mono_defaults.string_class, 1);
5849 string_array_klass = klass;
5851 klass = mono_array_class_get (mono_defaults.object_class, 1);
5854 mono_atomic_store_release (&object_array_klass, klass);
5857 MONO_OBJECT_SETREF (this_obj, method, method);
5859 MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5860 MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5861 this_obj->async_result = NULL;
5862 this_obj->call_type = CallType_Sync;
5864 names = g_new (char *, sig->param_count);
5865 mono_method_get_param_names (method->method, (const char **) names);
5866 MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5868 for (i = 0; i < sig->param_count; i++) {
5869 name = mono_string_new (domain, names [i]);
5870 mono_array_setref (this_obj->names, i, name);
5874 for (i = 0, j = 0; i < sig->param_count; i++) {
5875 if (sig->params [i]->byref) {
5877 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5878 mono_array_setref (this_obj->args, i, arg);
5882 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5886 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5889 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
5893 #ifndef DISABLE_REMOTING
5895 * mono_remoting_invoke:
5896 * @real_proxy: pointer to a RealProxy object
5897 * @msg: The MonoMethodMessage to execute
5898 * @exc: used to store exceptions
5899 * @out_args: used to store output arguments
5901 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5902 * IMessage interface and it is not trivial to extract results from there. So
5903 * we call an helper method PrivateInvoke instead of calling
5904 * RealProxy::Invoke() directly.
5906 * Returns: the result object.
5909 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5910 MonoObject **exc, MonoArray **out_args)
5912 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5915 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5918 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5920 real_proxy->vtable->domain->private_invoke_method = im;
5923 pa [0] = real_proxy;
5928 return mono_runtime_invoke (im, NULL, pa, exc);
5933 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5934 MonoObject **exc, MonoArray **out_args)
5936 static MonoClass *object_array_klass;
5939 MonoMethodSignature *sig;
5941 int i, j, outarg_count = 0;
5943 #ifndef DISABLE_REMOTING
5944 if (target && mono_object_is_transparent_proxy (target)) {
5945 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5946 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
5947 target = tp->rp->unwrapped_server;
5949 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5954 domain = mono_domain_get ();
5955 method = msg->method->method;
5956 sig = mono_method_signature (method);
5958 for (i = 0; i < sig->param_count; i++) {
5959 if (sig->params [i]->byref)
5963 if (!object_array_klass) {
5966 klass = mono_array_class_get (mono_defaults.object_class, 1);
5969 mono_memory_barrier ();
5970 object_array_klass = klass;
5973 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
5976 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5978 for (i = 0, j = 0; i < sig->param_count; i++) {
5979 if (sig->params [i]->byref) {
5981 arg = mono_array_get (msg->args, gpointer, i);
5982 mono_array_setref (*out_args, j, arg);
5991 * mono_object_to_string:
5993 * @exc: Any exception thrown by ToString (). May be NULL.
5995 * Returns: the result of calling ToString () on an object.
5998 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6000 static MonoMethod *to_string = NULL;
6007 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6009 method = mono_object_get_virtual_method (obj, to_string);
6011 // Unbox value type if needed
6012 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6013 target = mono_object_unbox (obj);
6016 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6020 * mono_print_unhandled_exception:
6021 * @exc: The exception
6023 * Prints the unhandled exception.
6026 mono_print_unhandled_exception (MonoObject *exc)
6029 char *message = (char*)"";
6030 gboolean free_message = FALSE;
6033 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6034 message = g_strdup ("OutOfMemoryException");
6035 free_message = TRUE;
6036 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6037 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6038 free_message = TRUE;
6041 if (((MonoException*)exc)->native_trace_ips) {
6042 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6043 free_message = TRUE;
6045 MonoObject *other_exc = NULL;
6046 str = mono_object_to_string (exc, &other_exc);
6048 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6049 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6051 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6052 original_backtrace, nested_backtrace);
6054 g_free (original_backtrace);
6055 g_free (nested_backtrace);
6056 free_message = TRUE;
6058 message = mono_string_to_utf8_checked (str, &error);
6059 if (!mono_error_ok (&error)) {
6060 mono_error_cleanup (&error);
6061 message = (char *) "";
6063 free_message = TRUE;
6070 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6071 * exc->vtable->klass->name, message);
6073 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6080 * mono_delegate_ctor:
6081 * @this: pointer to an uninitialized delegate object
6082 * @target: target object
6083 * @addr: pointer to native code
6086 * Initialize a delegate and sets a specific method, not the one
6087 * associated with addr. This is useful when sharing generic code.
6088 * In that case addr will most probably not be associated with the
6089 * correct instantiation of the method.
6092 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6094 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6096 g_assert (this_obj);
6099 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6102 delegate->method = method;
6104 mono_stats.delegate_creations++;
6106 #ifndef DISABLE_REMOTING
6107 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6109 method = mono_marshal_get_remoting_invoke (method);
6110 delegate->method_ptr = mono_compile_method (method);
6111 MONO_OBJECT_SETREF (delegate, target, target);
6115 delegate->method_ptr = addr;
6116 MONO_OBJECT_SETREF (delegate, target, target);
6119 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6123 * mono_delegate_ctor:
6124 * @this: pointer to an uninitialized delegate object
6125 * @target: target object
6126 * @addr: pointer to native code
6128 * This is used to initialize a delegate.
6131 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6133 MonoDomain *domain = mono_domain_get ();
6135 MonoMethod *method = NULL;
6139 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6141 if (!ji && domain != mono_get_root_domain ())
6142 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6144 method = mono_jit_info_get_method (ji);
6145 g_assert (!method->klass->generic_container);
6148 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6152 * mono_method_call_message_new:
6153 * @method: method to encapsulate
6154 * @params: parameters to the method
6155 * @invoke: optional, delegate invoke.
6156 * @cb: async callback delegate.
6157 * @state: state passed to the async callback.
6159 * Translates arguments pointers into a MonoMethodMessage.
6162 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6163 MonoDelegate **cb, MonoObject **state)
6165 MonoDomain *domain = mono_domain_get ();
6166 MonoMethodSignature *sig = mono_method_signature (method);
6167 MonoMethodMessage *msg;
6170 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6173 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6174 count = sig->param_count - 2;
6176 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6177 count = sig->param_count;
6180 for (i = 0; i < count; i++) {
6185 if (sig->params [i]->byref)
6186 vpos = *((gpointer *)params [i]);
6190 class = mono_class_from_mono_type (sig->params [i]);
6192 if (class->valuetype)
6193 arg = mono_value_box (domain, class, vpos);
6195 arg = *((MonoObject **)vpos);
6197 mono_array_setref (msg->args, i, arg);
6200 if (cb != NULL && state != NULL) {
6201 *cb = *((MonoDelegate **)params [i]);
6203 *state = *((MonoObject **)params [i]);
6210 * mono_method_return_message_restore:
6212 * Restore results from message based processing back to arguments pointers
6215 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6217 MonoMethodSignature *sig = mono_method_signature (method);
6218 int i, j, type, size, out_len;
6220 if (out_args == NULL)
6222 out_len = mono_array_length (out_args);
6226 for (i = 0, j = 0; i < sig->param_count; i++) {
6227 MonoType *pt = sig->params [i];
6232 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6234 arg = mono_array_get (out_args, gpointer, j);
6237 g_assert (type != MONO_TYPE_VOID);
6239 if (MONO_TYPE_IS_REFERENCE (pt)) {
6240 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6243 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6244 size = mono_class_value_size (class, NULL);
6245 if (class->has_references)
6246 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6248 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6250 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6251 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6260 #ifndef DISABLE_REMOTING
6263 * mono_load_remote_field:
6264 * @this: pointer to an object
6265 * @klass: klass of the object containing @field
6266 * @field: the field to load
6267 * @res: a storage to store the result
6269 * This method is called by the runtime on attempts to load fields of
6270 * transparent proxy objects. @this points to such TP, @klass is the class of
6271 * the object containing @field. @res is a storage location which can be
6272 * used to store the result.
6274 * Returns: an address pointing to the value of field.
6277 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6279 static MonoMethod *getter = NULL;
6280 MonoDomain *domain = mono_domain_get ();
6281 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6282 MonoClass *field_class;
6283 MonoMethodMessage *msg;
6284 MonoArray *out_args;
6288 g_assert (mono_object_is_transparent_proxy (this_obj));
6289 g_assert (res != NULL);
6291 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6292 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6297 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6301 field_class = mono_class_from_mono_type (field->type);
6303 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6304 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6305 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6307 full_name = mono_type_get_full_name (klass);
6308 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6309 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6312 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6314 if (exc) mono_raise_exception ((MonoException *)exc);
6316 if (mono_array_length (out_args) == 0)
6319 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6321 if (field_class->valuetype) {
6322 return ((char *)*res) + sizeof (MonoObject);
6328 * mono_load_remote_field_new:
6333 * Missing documentation.
6336 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6338 static MonoMethod *getter = NULL;
6339 MonoDomain *domain = mono_domain_get ();
6340 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6341 MonoClass *field_class;
6342 MonoMethodMessage *msg;
6343 MonoArray *out_args;
6344 MonoObject *exc, *res;
6347 g_assert (mono_object_is_transparent_proxy (this_obj));
6349 field_class = mono_class_from_mono_type (field->type);
6351 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6353 if (field_class->valuetype) {
6354 res = mono_object_new (domain, field_class);
6355 val = ((gchar *) res) + sizeof (MonoObject);
6359 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6364 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6368 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6369 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6371 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6373 full_name = mono_type_get_full_name (klass);
6374 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6375 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6378 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6380 if (exc) mono_raise_exception ((MonoException *)exc);
6382 if (mono_array_length (out_args) == 0)
6385 res = mono_array_get (out_args, MonoObject *, 0);
6391 * mono_store_remote_field:
6392 * @this_obj: pointer to an object
6393 * @klass: klass of the object containing @field
6394 * @field: the field to load
6395 * @val: the value/object to store
6397 * This method is called by the runtime on attempts to store fields of
6398 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6399 * the object containing @field. @val is the new value to store in @field.
6402 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6404 static MonoMethod *setter = NULL;
6405 MonoDomain *domain = mono_domain_get ();
6406 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6407 MonoClass *field_class;
6408 MonoMethodMessage *msg;
6409 MonoArray *out_args;
6414 g_assert (mono_object_is_transparent_proxy (this_obj));
6416 field_class = mono_class_from_mono_type (field->type);
6418 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6419 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6420 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6425 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6429 if (field_class->valuetype)
6430 arg = mono_value_box (domain, field_class, val);
6432 arg = *((MonoObject **)val);
6435 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6436 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6438 full_name = mono_type_get_full_name (klass);
6439 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6440 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6441 mono_array_setref (msg->args, 2, arg);
6444 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6446 if (exc) mono_raise_exception ((MonoException *)exc);
6450 * mono_store_remote_field_new:
6456 * Missing documentation
6459 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6461 static MonoMethod *setter = NULL;
6462 MonoDomain *domain = mono_domain_get ();
6463 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6464 MonoClass *field_class;
6465 MonoMethodMessage *msg;
6466 MonoArray *out_args;
6470 g_assert (mono_object_is_transparent_proxy (this_obj));
6472 field_class = mono_class_from_mono_type (field->type);
6474 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6475 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6476 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6481 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6485 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6486 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6488 full_name = mono_type_get_full_name (klass);
6489 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6490 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6491 mono_array_setref (msg->args, 2, arg);
6494 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6496 if (exc) mono_raise_exception ((MonoException *)exc);
6501 * mono_create_ftnptr:
6503 * Given a function address, create a function descriptor for it.
6504 * This is only needed on some platforms.
6507 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6509 return callbacks.create_ftnptr (domain, addr);
6513 * mono_get_addr_from_ftnptr:
6515 * Given a pointer to a function descriptor, return the function address.
6516 * This is only needed on some platforms.
6519 mono_get_addr_from_ftnptr (gpointer descr)
6521 return callbacks.get_addr_from_ftnptr (descr);
6525 * mono_string_chars:
6528 * Returns a pointer to the UCS16 characters stored in the MonoString
6531 mono_string_chars (MonoString *s)
6537 * mono_string_length:
6540 * Returns the lenght in characters of the string
6543 mono_string_length (MonoString *s)
6549 * mono_array_length:
6550 * @array: a MonoArray*
6552 * Returns the total number of elements in the array. This works for
6553 * both vectors and multidimensional arrays.
6556 mono_array_length (MonoArray *array)
6558 return array->max_length;
6562 * mono_array_addr_with_size:
6563 * @array: a MonoArray*
6564 * @size: size of the array elements
6565 * @idx: index into the array
6567 * Returns the address of the @idx element in the array.
6570 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6572 return ((char*)(array)->vector) + size * idx;