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/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include "cominterop.h"
49 #define NEED_TO_ZERO_PTRFREE 1
50 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
51 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
52 #ifdef HAVE_GC_GCJ_MALLOC
53 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
61 #define GC_NO_DESCRIPTOR (NULL)
62 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
66 #define NEED_TO_ZERO_PTRFREE 1
67 #define GC_NO_DESCRIPTOR (NULL)
68 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
69 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
70 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
84 free_main_args (void);
87 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
90 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
91 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
92 static mono_mutex_t ldstr_section;
94 static gboolean profile_allocs = TRUE;
97 mono_runtime_object_init (MonoObject *this)
99 MonoMethod *method = NULL;
100 MonoClass *klass = this->vtable->klass;
102 method = mono_class_get_method_from_name (klass, ".ctor", 0);
104 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
106 if (method->klass->valuetype)
107 this = mono_object_unbox (this);
108 mono_runtime_invoke (method, this, NULL, NULL);
111 /* The pseudo algorithm for type initialization from the spec
112 Note it doesn't say anything about domains - only threads.
114 2. If the type is initialized you are done.
115 2.1. If the type is not yet initialized, try to take an
117 2.2. If successful, record this thread as responsible for
118 initializing the type and proceed to step 2.3.
119 2.2.1. If not, see whether this thread or any thread
120 waiting for this thread to complete already holds the lock.
121 2.2.2. If so, return since blocking would create a deadlock. This thread
122 will now see an incompletely initialized state for the type,
123 but no deadlock will arise.
124 2.2.3 If not, block until the type is initialized then return.
125 2.3 Initialize the parent type and then all interfaces implemented
127 2.4 Execute the type initialization code for this type.
128 2.5 Mark the type as initialized, release the initialization lock,
129 awaken any threads waiting for this type to be initialized,
136 guint32 initializing_tid;
137 guint32 waiting_count;
139 mono_mutex_t initialization_section;
140 } TypeInitializationLock;
142 /* for locking access to type_initialization_hash and blocked_thread_hash */
143 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
144 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
145 static mono_mutex_t type_initialization_section;
147 /* from vtable to lock */
148 static GHashTable *type_initialization_hash;
150 /* from thread id to thread id being waited on */
151 static GHashTable *blocked_thread_hash;
154 static MonoThread *main_thread;
156 /* Functions supplied by the runtime */
157 static MonoRuntimeCallbacks callbacks;
160 * mono_thread_set_main:
161 * @thread: thread to set as the main thread
163 * This function can be used to instruct the runtime to treat @thread
164 * as the main thread, ie, the thread that would normally execute the Main()
165 * method. This basically means that at the end of @thread, the runtime will
166 * wait for the existing foreground threads to quit and other such details.
169 mono_thread_set_main (MonoThread *thread)
171 static gboolean registered = FALSE;
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
178 main_thread = thread;
182 mono_thread_get_main (void)
188 mono_type_initialization_init (void)
190 mono_mutex_init_recursive (&type_initialization_section);
191 type_initialization_hash = g_hash_table_new (NULL, NULL);
192 blocked_thread_hash = g_hash_table_new (NULL, NULL);
193 mono_mutex_init_recursive (&ldstr_section);
197 mono_type_initialization_cleanup (void)
200 /* This is causing race conditions with
201 * mono_release_type_locks
203 mono_mutex_destroy (&type_initialization_section);
204 g_hash_table_destroy (type_initialization_hash);
205 type_initialization_hash = NULL;
207 mono_mutex_destroy (&ldstr_section);
208 g_hash_table_destroy (blocked_thread_hash);
209 blocked_thread_hash = NULL;
215 * get_type_init_exception_for_vtable:
217 * Return the stored type initialization exception for VTABLE.
219 static MonoException*
220 get_type_init_exception_for_vtable (MonoVTable *vtable)
222 MonoDomain *domain = vtable->domain;
223 MonoClass *klass = vtable->klass;
227 if (!vtable->init_failed)
228 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
231 * If the initializing thread was rudely aborted, the exception is not stored
235 mono_domain_lock (domain);
236 if (domain->type_init_exception_hash)
237 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
238 mono_domain_unlock (domain);
241 if (klass->name_space && *klass->name_space)
242 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
244 full_name = g_strdup (klass->name);
245 ex = mono_get_exception_type_initialization (full_name, NULL);
252 * mono_runtime_class_init:
253 * @vtable: vtable that needs to be initialized
255 * This routine calls the class constructor for @vtable.
258 mono_runtime_class_init (MonoVTable *vtable)
260 mono_runtime_class_init_full (vtable, TRUE);
264 * mono_runtime_class_init_full:
265 * @vtable that neeeds to be initialized
266 * @raise_exception is TRUE, exceptions are raised intead of returned
270 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
273 MonoException *exc_to_throw;
274 MonoMethod *method = NULL;
278 if (vtable->initialized)
282 klass = vtable->klass;
284 if (!klass->image->checked_module_cctor) {
285 mono_image_check_for_module_cctor (klass->image);
286 if (klass->image->has_module_cctor) {
288 MonoClass *module_klass;
289 MonoVTable *module_vtable;
291 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
293 exc = mono_error_convert_to_exception (&error);
295 mono_raise_exception (exc);
299 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
302 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
307 method = mono_class_get_cctor (klass);
310 MonoDomain *domain = vtable->domain;
311 TypeInitializationLock *lock;
312 guint32 tid = GetCurrentThreadId();
313 int do_initialization = 0;
314 MonoDomain *last_domain = NULL;
316 mono_type_initialization_lock ();
317 /* double check... */
318 if (vtable->initialized) {
319 mono_type_initialization_unlock ();
322 if (vtable->init_failed) {
323 mono_type_initialization_unlock ();
325 /* The type initialization already failed once, rethrow the same exception */
327 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
328 return get_type_init_exception_for_vtable (vtable);
330 lock = g_hash_table_lookup (type_initialization_hash, vtable);
332 /* This thread will get to do the initialization */
333 if (mono_domain_get () != domain) {
334 /* Transfer into the target domain */
335 last_domain = mono_domain_get ();
336 if (!mono_domain_set (domain, FALSE)) {
337 vtable->initialized = 1;
338 mono_type_initialization_unlock ();
340 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
341 return mono_get_exception_appdomain_unloaded ();
344 lock = g_malloc (sizeof(TypeInitializationLock));
345 mono_mutex_init_recursive (&lock->initialization_section);
346 lock->initializing_tid = tid;
347 lock->waiting_count = 1;
349 /* grab the vtable lock while this thread still owns type_initialization_section */
350 mono_mutex_lock (&lock->initialization_section);
351 g_hash_table_insert (type_initialization_hash, vtable, lock);
352 do_initialization = 1;
355 TypeInitializationLock *pending_lock;
357 if (lock->initializing_tid == tid || lock->done) {
358 mono_type_initialization_unlock ();
361 /* see if the thread doing the initialization is already blocked on this thread */
362 blocked = GUINT_TO_POINTER (lock->initializing_tid);
363 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
364 if (pending_lock->initializing_tid == tid) {
365 if (!pending_lock->done) {
366 mono_type_initialization_unlock ();
369 /* the thread doing the initialization is blocked on this thread,
370 but on a lock that has already been freed. It just hasn't got
375 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
377 ++lock->waiting_count;
378 /* record the fact that we are waiting on the initializing thread */
379 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
381 mono_type_initialization_unlock ();
383 if (do_initialization) {
384 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
386 /* If the initialization failed, mark the class as unusable. */
387 /* Avoid infinite loops */
389 (klass->image == mono_defaults.corlib &&
390 !strcmp (klass->name_space, "System") &&
391 !strcmp (klass->name, "TypeInitializationException")))) {
392 vtable->init_failed = 1;
394 if (klass->name_space && *klass->name_space)
395 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
397 full_name = g_strdup (klass->name);
398 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
402 * Store the exception object so it could be thrown on subsequent
405 mono_domain_lock (domain);
406 if (!domain->type_init_exception_hash)
407 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
408 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
409 mono_domain_unlock (domain);
413 mono_domain_set (last_domain, TRUE);
415 mono_mutex_unlock (&lock->initialization_section);
417 /* this just blocks until the initializing thread is done */
418 mono_mutex_lock (&lock->initialization_section);
419 mono_mutex_unlock (&lock->initialization_section);
422 mono_type_initialization_lock ();
423 if (lock->initializing_tid != tid)
424 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
425 --lock->waiting_count;
426 if (lock->waiting_count == 0) {
427 mono_mutex_destroy (&lock->initialization_section);
428 g_hash_table_remove (type_initialization_hash, vtable);
431 mono_memory_barrier ();
432 if (!vtable->init_failed)
433 vtable->initialized = 1;
434 mono_type_initialization_unlock ();
436 if (vtable->init_failed) {
437 /* Either we were the initializing thread or we waited for the initialization */
439 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
440 return get_type_init_exception_for_vtable (vtable);
443 vtable->initialized = 1;
450 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
452 MonoVTable *vtable = (MonoVTable*)key;
454 TypeInitializationLock *lock = (TypeInitializationLock*) value;
455 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
458 * Have to set this since it cannot be set by the normal code in
459 * mono_runtime_class_init (). In this case, the exception object is not stored,
460 * and get_type_init_exception_for_class () needs to be aware of this.
462 vtable->init_failed = 1;
463 mono_mutex_unlock (&lock->initialization_section);
464 --lock->waiting_count;
465 if (lock->waiting_count == 0) {
466 mono_mutex_destroy (&lock->initialization_section);
475 mono_release_type_locks (MonoInternalThread *thread)
477 mono_type_initialization_lock ();
478 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
479 mono_type_initialization_unlock ();
483 default_trampoline (MonoMethod *method)
489 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
491 g_assert_not_reached ();
496 #ifndef DISABLE_REMOTING
499 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
501 g_error ("remoting not installed");
505 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
509 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
511 g_assert_not_reached ();
515 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
516 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
517 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
518 static MonoImtThunkBuilder imt_thunk_builder = NULL;
519 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
520 #if (MONO_IMT_SIZE > 32)
521 #error "MONO_IMT_SIZE cannot be larger than 32"
525 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
527 memcpy (&callbacks, cbs, sizeof (*cbs));
530 MonoRuntimeCallbacks*
531 mono_get_runtime_callbacks (void)
537 mono_install_trampoline (MonoTrampoline func)
539 arch_create_jit_trampoline = func? func: default_trampoline;
543 mono_install_jump_trampoline (MonoJumpTrampoline func)
545 arch_create_jump_trampoline = func? func: default_jump_trampoline;
548 #ifndef DISABLE_REMOTING
550 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
552 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
557 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
559 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
563 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
564 imt_thunk_builder = func;
567 static MonoCompileFunc default_mono_compile_method = NULL;
570 * mono_install_compile_method:
571 * @func: function to install
573 * This is a VM internal routine
576 mono_install_compile_method (MonoCompileFunc func)
578 default_mono_compile_method = func;
582 * mono_compile_method:
583 * @method: The method to compile.
585 * This JIT-compiles the method, and returns the pointer to the native code
589 mono_compile_method (MonoMethod *method)
591 if (!default_mono_compile_method) {
592 g_error ("compile method called on uninitialized runtime");
595 return default_mono_compile_method (method);
599 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
601 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
605 mono_runtime_create_delegate_trampoline (MonoClass *klass)
607 return arch_create_delegate_trampoline (mono_domain_get (), klass);
610 static MonoFreeMethodFunc default_mono_free_method = NULL;
613 * mono_install_free_method:
614 * @func: pointer to the MonoFreeMethodFunc used to release a method
616 * This is an internal VM routine, it is used for the engines to
617 * register a handler to release the resources associated with a method.
619 * Methods are freed when no more references to the delegate that holds
623 mono_install_free_method (MonoFreeMethodFunc func)
625 default_mono_free_method = func;
629 * mono_runtime_free_method:
630 * @domain; domain where the method is hosted
631 * @method: method to release
633 * This routine is invoked to free the resources associated with
634 * a method that has been JIT compiled. This is used to discard
635 * methods that were used only temporarily (for example, used in marshalling)
639 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
641 if (default_mono_free_method != NULL)
642 default_mono_free_method (domain, method);
644 mono_method_clear_object (domain, method);
646 mono_free_method (method);
650 * The vtables in the root appdomain are assumed to be reachable by other
651 * roots, and we don't use typed allocation in the other domains.
654 /* The sync block is no longer a GC pointer */
655 #define GC_HEADER_BITMAP (0)
657 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
660 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
662 MonoClassField *field;
668 max_size = mono_class_data_size (class) / sizeof (gpointer);
670 max_size = class->instance_size / sizeof (gpointer);
671 if (max_size > size) {
672 g_assert (offset <= 0);
673 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
678 /*An Ephemeron cannot be marked by sgen*/
679 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
681 memset (bitmap, 0, size / 8);
686 for (p = class; p != NULL; p = p->parent) {
687 gpointer iter = NULL;
688 while ((field = mono_class_get_fields (p, &iter))) {
692 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
694 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
697 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
700 /* FIXME: should not happen, flag as type load error */
701 if (field->type->byref)
704 if (static_fields && field->offset == -1)
708 pos = field->offset / sizeof (gpointer);
711 type = mono_type_get_underlying_type (field->type);
712 switch (type->type) {
715 case MONO_TYPE_FNPTR:
717 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
722 if (class->image != mono_defaults.corlib)
725 case MONO_TYPE_STRING:
726 case MONO_TYPE_SZARRAY:
727 case MONO_TYPE_CLASS:
728 case MONO_TYPE_OBJECT:
729 case MONO_TYPE_ARRAY:
730 g_assert ((field->offset % sizeof(gpointer)) == 0);
732 g_assert (pos < size || pos <= max_size);
733 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
734 *max_set = MAX (*max_set, pos);
736 case MONO_TYPE_GENERICINST:
737 if (!mono_type_generic_inst_is_valuetype (type)) {
738 g_assert ((field->offset % sizeof(gpointer)) == 0);
740 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
741 *max_set = MAX (*max_set, pos);
746 case MONO_TYPE_VALUETYPE: {
747 MonoClass *fclass = mono_class_from_mono_type (field->type);
748 if (fclass->has_references) {
749 /* remove the object header */
750 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
764 case MONO_TYPE_BOOLEAN:
768 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
779 * mono_class_compute_bitmap:
781 * Mono internal function to compute a bitmap of reference fields in a class.
784 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
786 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
791 * similar to the above, but sets the bits in the bitmap for any non-ref field
792 * and ignores static fields
795 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
797 MonoClassField *field;
802 max_size = class->instance_size / sizeof (gpointer);
803 if (max_size >= size) {
804 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
807 for (p = class; p != NULL; p = p->parent) {
808 gpointer iter = NULL;
809 while ((field = mono_class_get_fields (p, &iter))) {
812 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
814 /* FIXME: should not happen, flag as type load error */
815 if (field->type->byref)
818 pos = field->offset / sizeof (gpointer);
821 type = mono_type_get_underlying_type (field->type);
822 switch (type->type) {
823 #if SIZEOF_VOID_P == 8
827 case MONO_TYPE_FNPTR:
832 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
833 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
834 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
837 #if SIZEOF_VOID_P == 4
841 case MONO_TYPE_FNPTR:
846 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
847 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
848 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
854 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
855 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
856 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
859 case MONO_TYPE_BOOLEAN:
862 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
864 case MONO_TYPE_STRING:
865 case MONO_TYPE_SZARRAY:
866 case MONO_TYPE_CLASS:
867 case MONO_TYPE_OBJECT:
868 case MONO_TYPE_ARRAY:
870 case MONO_TYPE_GENERICINST:
871 if (!mono_type_generic_inst_is_valuetype (type)) {
876 case MONO_TYPE_VALUETYPE: {
877 MonoClass *fclass = mono_class_from_mono_type (field->type);
878 /* remove the object header */
879 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
883 g_assert_not_reached ();
892 * mono_class_insecure_overlapping:
893 * check if a class with explicit layout has references and non-references
894 * fields overlapping.
896 * Returns: TRUE if it is insecure to load the type.
899 mono_class_insecure_overlapping (MonoClass *klass)
903 gsize default_bitmap [4] = {0};
905 gsize default_nrbitmap [4] = {0};
906 int i, insecure = FALSE;
909 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
910 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
912 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
913 int idx = i % (sizeof (bitmap [0]) * 8);
914 if (bitmap [idx] & nrbitmap [idx]) {
919 if (bitmap != default_bitmap)
921 if (nrbitmap != default_nrbitmap)
924 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
932 mono_string_alloc (int length)
934 return mono_string_new_size (mono_domain_get (), length);
938 mono_class_compute_gc_descriptor (MonoClass *class)
942 gsize default_bitmap [4] = {0};
943 static gboolean gcj_inited = FALSE;
948 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
949 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
950 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
951 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
953 #ifdef HAVE_GC_GCJ_MALLOC
955 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
959 #ifdef GC_REDIRECT_TO_LOCAL
960 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
961 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
963 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
964 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
969 mono_loader_unlock ();
973 mono_class_init (class);
975 if (class->gc_descr_inited)
978 class->gc_descr_inited = TRUE;
979 class->gc_descr = GC_NO_DESCRIPTOR;
981 bitmap = default_bitmap;
982 if (class == mono_defaults.string_class) {
983 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
984 } else if (class->rank) {
985 mono_class_compute_gc_descriptor (class->element_class);
986 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
988 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
989 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
990 class->name_space, class->name);*/
992 /* remove the object header */
993 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
994 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));
995 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
996 class->name_space, class->name);*/
997 if (bitmap != default_bitmap)
1001 /*static int count = 0;
1004 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1005 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1007 if (class->gc_descr == GC_NO_DESCRIPTOR)
1008 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1010 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1011 if (bitmap != default_bitmap)
1017 * field_is_special_static:
1018 * @fklass: The MonoClass to look up.
1019 * @field: The MonoClassField describing the field.
1021 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1022 * SPECIAL_STATIC_NONE otherwise.
1025 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1027 MonoCustomAttrInfo *ainfo;
1029 ainfo = mono_custom_attrs_from_field (fklass, field);
1032 for (i = 0; i < ainfo->num_attrs; ++i) {
1033 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1034 if (klass->image == mono_defaults.corlib) {
1035 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1036 mono_custom_attrs_free (ainfo);
1037 return SPECIAL_STATIC_THREAD;
1039 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1040 mono_custom_attrs_free (ainfo);
1041 return SPECIAL_STATIC_CONTEXT;
1045 mono_custom_attrs_free (ainfo);
1046 return SPECIAL_STATIC_NONE;
1049 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1050 #define mix(a,b,c) { \
1051 a -= c; a ^= rot(c, 4); c += b; \
1052 b -= a; b ^= rot(a, 6); a += c; \
1053 c -= b; c ^= rot(b, 8); b += a; \
1054 a -= c; a ^= rot(c,16); c += b; \
1055 b -= a; b ^= rot(a,19); a += c; \
1056 c -= b; c ^= rot(b, 4); b += a; \
1058 #define final(a,b,c) { \
1059 c ^= b; c -= rot(b,14); \
1060 a ^= c; a -= rot(c,11); \
1061 b ^= a; b -= rot(a,25); \
1062 c ^= b; c -= rot(b,16); \
1063 a ^= c; a -= rot(c,4); \
1064 b ^= a; b -= rot(a,14); \
1065 c ^= b; c -= rot(b,24); \
1069 * mono_method_get_imt_slot:
1071 * The IMT slot is embedded into AOTed code, so this must return the same value
1072 * for the same method across all executions. This means:
1073 * - pointers shouldn't be used as hash values.
1074 * - mono_metadata_str_hash () should be used for hashing strings.
1077 mono_method_get_imt_slot (MonoMethod *method)
1079 MonoMethodSignature *sig;
1081 guint32 *hashes_start, *hashes;
1085 /* This can be used to stress tests the collision code */
1089 * We do this to simplify generic sharing. It will hurt
1090 * performance in cases where a class implements two different
1091 * instantiations of the same generic interface.
1092 * The code in build_imt_slots () depends on this.
1094 if (method->is_inflated)
1095 method = ((MonoMethodInflated*)method)->declaring;
1097 sig = mono_method_signature (method);
1098 hashes_count = sig->param_count + 4;
1099 hashes_start = malloc (hashes_count * sizeof (guint32));
1100 hashes = hashes_start;
1102 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1103 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1104 method->klass->name_space, method->klass->name, method->name);
1107 /* Initialize hashes */
1108 hashes [0] = mono_metadata_str_hash (method->klass->name);
1109 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1110 hashes [2] = mono_metadata_str_hash (method->name);
1111 hashes [3] = mono_metadata_type_hash (sig->ret);
1112 for (i = 0; i < sig->param_count; i++) {
1113 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1116 /* Setup internal state */
1117 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1119 /* Handle most of the hashes */
1120 while (hashes_count > 3) {
1129 /* Handle the last 3 hashes (all the case statements fall through) */
1130 switch (hashes_count) {
1131 case 3 : c += hashes [2];
1132 case 2 : b += hashes [1];
1133 case 1 : a += hashes [0];
1135 case 0: /* nothing left to add */
1139 free (hashes_start);
1140 /* Report the result */
1141 return c % MONO_IMT_SIZE;
1150 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1151 guint32 imt_slot = mono_method_get_imt_slot (method);
1152 MonoImtBuilderEntry *entry;
1154 if (slot_num >= 0 && imt_slot != slot_num) {
1155 /* we build just a single imt slot and this is not it */
1159 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1160 entry->key = method;
1161 entry->value.vtable_slot = vtable_slot;
1162 entry->next = imt_builder [imt_slot];
1163 if (imt_builder [imt_slot] != NULL) {
1164 entry->children = imt_builder [imt_slot]->children + 1;
1165 if (entry->children == 1) {
1166 mono_stats.imt_slots_with_collisions++;
1167 *imt_collisions_bitmap |= (1 << imt_slot);
1170 entry->children = 0;
1171 mono_stats.imt_used_slots++;
1173 imt_builder [imt_slot] = entry;
1176 char *method_name = mono_method_full_name (method, TRUE);
1177 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1178 method, method_name, imt_slot, vtable_slot, entry->children);
1179 g_free (method_name);
1186 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1188 MonoMethod *method = e->key;
1189 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1193 method->klass->name_space,
1194 method->klass->name,
1197 printf (" * %s: NULL\n", message);
1203 compare_imt_builder_entries (const void *p1, const void *p2) {
1204 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1205 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1207 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1211 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1213 int count = end - start;
1214 int chunk_start = out_array->len;
1217 for (i = start; i < end; ++i) {
1218 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1219 item->key = sorted_array [i]->key;
1220 item->value = sorted_array [i]->value;
1221 item->has_target_code = sorted_array [i]->has_target_code;
1222 item->is_equals = TRUE;
1224 item->check_target_idx = out_array->len + 1;
1226 item->check_target_idx = 0;
1227 g_ptr_array_add (out_array, item);
1230 int middle = start + count / 2;
1231 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1233 item->key = sorted_array [middle]->key;
1234 item->is_equals = FALSE;
1235 g_ptr_array_add (out_array, item);
1236 imt_emit_ir (sorted_array, start, middle, out_array);
1237 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1243 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1244 int number_of_entries = entries->children + 1;
1245 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1246 GPtrArray *result = g_ptr_array_new ();
1247 MonoImtBuilderEntry *current_entry;
1250 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1251 sorted_array [i] = current_entry;
1253 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1255 /*for (i = 0; i < number_of_entries; i++) {
1256 print_imt_entry (" sorted array:", sorted_array [i], i);
1259 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1261 free (sorted_array);
1266 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1268 if (imt_builder_entry != NULL) {
1269 if (imt_builder_entry->children == 0 && !fail_tramp) {
1270 /* No collision, return the vtable slot contents */
1271 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1273 /* Collision, build the thunk */
1274 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1277 result = imt_thunk_builder (vtable, domain,
1278 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1279 for (i = 0; i < imt_ir->len; ++i)
1280 g_free (g_ptr_array_index (imt_ir, i));
1281 g_ptr_array_free (imt_ir, TRUE);
1293 static MonoImtBuilderEntry*
1294 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1297 * LOCKING: requires the loader and domain locks.
1301 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1305 guint32 imt_collisions_bitmap = 0;
1306 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1307 int method_count = 0;
1308 gboolean record_method_count_for_max_collisions = FALSE;
1309 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1312 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1314 for (i = 0; i < klass->interface_offsets_count; ++i) {
1315 MonoClass *iface = klass->interfaces_packed [i];
1316 int interface_offset = klass->interface_offsets_packed [i];
1317 int method_slot_in_interface, vt_slot;
1319 if (mono_class_has_variant_generic_params (iface))
1320 has_variant_iface = TRUE;
1322 mono_class_setup_methods (iface);
1323 vt_slot = interface_offset;
1324 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1327 if (slot_num >= 0 && iface->is_inflated) {
1329 * The imt slot of the method is the same as for its declaring method,
1330 * see the comment in mono_method_get_imt_slot (), so we can
1331 * avoid inflating methods which will be discarded by
1332 * add_imt_builder_entry anyway.
1334 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1335 if (mono_method_get_imt_slot (method) != slot_num) {
1340 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1341 if (method->is_generic) {
1342 has_generic_virtual = TRUE;
1347 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1348 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1353 if (extra_interfaces) {
1354 int interface_offset = klass->vtable_size;
1356 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1357 MonoClass* iface = list_item->data;
1358 int method_slot_in_interface;
1359 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1360 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1362 if (method->is_generic)
1363 has_generic_virtual = TRUE;
1364 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1366 interface_offset += iface->method.count;
1369 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1370 /* overwrite the imt slot only if we're building all the entries or if
1371 * we're building this specific one
1373 if (slot_num < 0 || i == slot_num) {
1374 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1377 if (imt_builder [i]) {
1378 MonoImtBuilderEntry *entry;
1380 /* Link entries with imt_builder [i] */
1381 for (entry = entries; entry->next; entry = entry->next) {
1383 MonoMethod *method = (MonoMethod*)entry->key;
1384 char *method_name = mono_method_full_name (method, TRUE);
1385 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1386 g_free (method_name);
1389 entry->next = imt_builder [i];
1390 entries->children += imt_builder [i]->children + 1;
1392 imt_builder [i] = entries;
1395 if (has_generic_virtual || has_variant_iface) {
1397 * There might be collisions later when the the thunk is expanded.
1399 imt_collisions_bitmap |= (1 << i);
1402 * The IMT thunk might be called with an instance of one of the
1403 * generic virtual methods, so has to fallback to the IMT trampoline.
1405 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1407 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1410 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1414 if (imt_builder [i] != NULL) {
1415 int methods_in_slot = imt_builder [i]->children + 1;
1416 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1417 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1418 record_method_count_for_max_collisions = TRUE;
1420 method_count += methods_in_slot;
1424 mono_stats.imt_number_of_methods += method_count;
1425 if (record_method_count_for_max_collisions) {
1426 mono_stats.imt_method_count_when_max_collisions = method_count;
1429 for (i = 0; i < MONO_IMT_SIZE; i++) {
1430 MonoImtBuilderEntry* entry = imt_builder [i];
1431 while (entry != NULL) {
1432 MonoImtBuilderEntry* next = entry->next;
1438 /* we OR the bitmap since we may build just a single imt slot at a time */
1439 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1443 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1444 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1448 * mono_vtable_build_imt_slot:
1449 * @vtable: virtual object table struct
1450 * @imt_slot: slot in the IMT table
1452 * Fill the given @imt_slot in the IMT table of @vtable with
1453 * a trampoline or a thunk for the case of collisions.
1454 * This is part of the internal mono API.
1456 * LOCKING: Take the domain lock.
1459 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1461 gpointer *imt = (gpointer*)vtable;
1462 imt -= MONO_IMT_SIZE;
1463 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1465 /* no support for extra interfaces: the proxy objects will need
1466 * to build the complete IMT
1467 * Update and heck needs to ahppen inside the proper domain lock, as all
1468 * the changes made to a MonoVTable.
1470 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1471 mono_domain_lock (vtable->domain);
1472 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1473 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1474 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1475 mono_domain_unlock (vtable->domain);
1476 mono_loader_unlock ();
1481 * The first two free list entries both belong to the wait list: The
1482 * first entry is the pointer to the head of the list and the second
1483 * entry points to the last element. That way appending and removing
1484 * the first element are both O(1) operations.
1486 #ifdef MONO_SMALL_CONFIG
1487 #define NUM_FREE_LISTS 6
1489 #define NUM_FREE_LISTS 12
1491 #define FIRST_FREE_LIST_SIZE 64
1492 #define MAX_WAIT_LENGTH 50
1493 #define THUNK_THRESHOLD 10
1496 * LOCKING: The domain lock must be held.
1499 init_thunk_free_lists (MonoDomain *domain)
1501 if (domain->thunk_free_lists)
1503 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1507 list_index_for_size (int item_size)
1510 int size = FIRST_FREE_LIST_SIZE;
1512 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1521 * mono_method_alloc_generic_virtual_thunk:
1523 * @size: size in bytes
1525 * Allocs size bytes to be used for the code of a generic virtual
1526 * thunk. It's either allocated from the domain's code manager or
1527 * reused from a previously invalidated piece.
1529 * LOCKING: The domain lock must be held.
1532 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1534 static gboolean inited = FALSE;
1535 static int generic_virtual_thunks_size = 0;
1539 MonoThunkFreeList **l;
1541 init_thunk_free_lists (domain);
1543 size += sizeof (guint32);
1544 if (size < sizeof (MonoThunkFreeList))
1545 size = sizeof (MonoThunkFreeList);
1547 i = list_index_for_size (size);
1548 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1549 if ((*l)->size >= size) {
1550 MonoThunkFreeList *item = *l;
1552 return ((guint32*)item) + 1;
1556 /* no suitable item found - search lists of larger sizes */
1557 while (++i < NUM_FREE_LISTS) {
1558 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1561 g_assert (item->size > size);
1562 domain->thunk_free_lists [i] = item->next;
1563 return ((guint32*)item) + 1;
1566 /* still nothing found - allocate it */
1568 mono_counters_register ("Generic virtual thunk bytes",
1569 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1572 generic_virtual_thunks_size += size;
1574 p = mono_domain_code_reserve (domain, size);
1577 mono_domain_lock (domain);
1578 if (!domain->generic_virtual_thunks)
1579 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1580 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1581 mono_domain_unlock (domain);
1587 * LOCKING: The domain lock must be held.
1590 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1593 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1594 gboolean found = FALSE;
1596 mono_domain_lock (domain);
1597 if (!domain->generic_virtual_thunks)
1598 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1599 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1601 mono_domain_unlock (domain);
1604 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1606 init_thunk_free_lists (domain);
1608 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1609 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1610 int length = item->length;
1613 /* unlink the first item from the wait list */
1614 domain->thunk_free_lists [0] = item->next;
1615 domain->thunk_free_lists [0]->length = length - 1;
1617 i = list_index_for_size (item->size);
1619 /* put it in the free list */
1620 item->next = domain->thunk_free_lists [i];
1621 domain->thunk_free_lists [i] = item;
1625 if (domain->thunk_free_lists [1]) {
1626 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1627 domain->thunk_free_lists [0]->length++;
1629 g_assert (!domain->thunk_free_lists [0]);
1631 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1632 domain->thunk_free_lists [0]->length = 1;
1636 typedef struct _GenericVirtualCase {
1640 struct _GenericVirtualCase *next;
1641 } GenericVirtualCase;
1644 * get_generic_virtual_entries:
1646 * Return IMT entries for the generic virtual method instances and
1647 * variant interface methods for vtable slot
1650 static MonoImtBuilderEntry*
1651 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1653 GenericVirtualCase *list;
1654 MonoImtBuilderEntry *entries;
1656 mono_domain_lock (domain);
1657 if (!domain->generic_virtual_cases)
1658 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1660 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1663 for (; list; list = list->next) {
1664 MonoImtBuilderEntry *entry;
1666 if (list->count < THUNK_THRESHOLD)
1669 entry = g_new0 (MonoImtBuilderEntry, 1);
1670 entry->key = list->method;
1671 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1672 entry->has_target_code = 1;
1674 entry->children = entries->children + 1;
1675 entry->next = entries;
1679 mono_domain_unlock (domain);
1681 /* FIXME: Leaking memory ? */
1686 * mono_method_add_generic_virtual_invocation:
1688 * @vtable_slot: pointer to the vtable slot
1689 * @method: the inflated generic virtual method
1690 * @code: the method's code
1692 * Registers a call via unmanaged code to a generic virtual method
1693 * instantiation or variant interface method. If the number of calls reaches a threshold
1694 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1695 * virtual method thunk.
1698 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1699 gpointer *vtable_slot,
1700 MonoMethod *method, gpointer code)
1702 static gboolean inited = FALSE;
1703 static int num_added = 0;
1705 GenericVirtualCase *gvc, *list;
1706 MonoImtBuilderEntry *entries;
1710 mono_domain_lock (domain);
1711 if (!domain->generic_virtual_cases)
1712 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1714 /* Check whether the case was already added */
1715 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1718 if (gvc->method == method)
1723 /* If not found, make a new one */
1725 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1726 gvc->method = method;
1729 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1731 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1734 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1740 if (++gvc->count == THUNK_THRESHOLD) {
1741 gpointer *old_thunk = *vtable_slot;
1742 gpointer vtable_trampoline = NULL;
1743 gpointer imt_trampoline = NULL;
1745 if ((gpointer)vtable_slot < (gpointer)vtable) {
1746 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1747 int imt_slot = MONO_IMT_SIZE + displacement;
1749 /* Force the rebuild of the thunk at the next call */
1750 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1751 *vtable_slot = imt_trampoline;
1753 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1755 entries = get_generic_virtual_entries (domain, vtable_slot);
1757 sorted = imt_sort_slot_entries (entries);
1759 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1763 MonoImtBuilderEntry *next = entries->next;
1768 for (i = 0; i < sorted->len; ++i)
1769 g_free (g_ptr_array_index (sorted, i));
1770 g_ptr_array_free (sorted, TRUE);
1773 #ifndef __native_client__
1774 /* We don't re-use any thunks as there is a lot of overhead */
1775 /* to deleting and re-using code in Native Client. */
1776 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1777 invalidate_generic_virtual_thunk (domain, old_thunk);
1781 mono_domain_unlock (domain);
1784 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1787 * mono_class_vtable:
1788 * @domain: the application domain
1789 * @class: the class to initialize
1791 * VTables are domain specific because we create domain specific code, and
1792 * they contain the domain specific static class data.
1793 * On failure, NULL is returned, and class->exception_type is set.
1796 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1798 return mono_class_vtable_full (domain, class, FALSE);
1802 * mono_class_vtable_full:
1803 * @domain: the application domain
1804 * @class: the class to initialize
1805 * @raise_on_error if an exception should be raised on failure or not
1807 * VTables are domain specific because we create domain specific code, and
1808 * they contain the domain specific static class data.
1811 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1813 MonoClassRuntimeInfo *runtime_info;
1817 if (class->exception_type) {
1819 mono_raise_exception (mono_class_get_exception_for_failure (class));
1823 /* this check can be inlined in jitted code, too */
1824 runtime_info = class->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1827 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1831 * mono_class_try_get_vtable:
1832 * @domain: the application domain
1833 * @class: the class to initialize
1835 * This function tries to get the associated vtable from @class if
1836 * it was already created.
1839 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1841 MonoClassRuntimeInfo *runtime_info;
1845 runtime_info = class->runtime_info;
1846 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1847 return runtime_info->domain_vtables [domain->domain_id];
1852 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1854 size_t alloc_offset;
1857 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1858 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1859 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1861 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1862 g_assert ((imt_table_bytes & 7) == 4);
1869 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1873 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1876 MonoClassRuntimeInfo *runtime_info, *old_info;
1877 MonoClassField *field;
1879 int i, vtable_slots;
1880 size_t imt_table_bytes;
1882 guint32 vtable_size, class_size;
1885 gpointer *interface_offsets;
1887 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1888 mono_domain_lock (domain);
1889 runtime_info = class->runtime_info;
1890 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1891 mono_domain_unlock (domain);
1892 mono_loader_unlock ();
1893 return runtime_info->domain_vtables [domain->domain_id];
1895 if (!class->inited || class->exception_type) {
1896 if (!mono_class_init (class) || class->exception_type) {
1897 mono_domain_unlock (domain);
1898 mono_loader_unlock ();
1900 mono_raise_exception (mono_class_get_exception_for_failure (class));
1905 /* Array types require that their element type be valid*/
1906 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1907 MonoClass *element_class = class->element_class;
1908 if (!element_class->inited)
1909 mono_class_init (element_class);
1911 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1912 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1913 mono_class_setup_vtable (element_class);
1915 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1916 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1917 if (class->exception_type == MONO_EXCEPTION_NONE)
1918 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1919 mono_domain_unlock (domain);
1920 mono_loader_unlock ();
1922 mono_raise_exception (mono_class_get_exception_for_failure (class));
1928 * For some classes, mono_class_init () already computed class->vtable_size, and
1929 * that is all that is needed because of the vtable trampolines.
1931 if (!class->vtable_size)
1932 mono_class_setup_vtable (class);
1934 if (class->generic_class && !class->vtable)
1935 mono_class_check_vtable_constraints (class, NULL);
1937 /* Initialize klass->has_finalize */
1938 mono_class_has_finalizer (class);
1940 if (class->exception_type) {
1941 mono_domain_unlock (domain);
1942 mono_loader_unlock ();
1944 mono_raise_exception (mono_class_get_exception_for_failure (class));
1948 vtable_slots = class->vtable_size;
1949 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1950 class_size = mono_class_data_size (class);
1955 if (class->interface_offsets_count) {
1956 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1957 mono_stats.imt_number_of_tables++;
1958 mono_stats.imt_tables_size += imt_table_bytes;
1960 imt_table_bytes = 0;
1963 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1966 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1968 mono_stats.used_class_count++;
1969 mono_stats.class_vtable_size += vtable_size;
1971 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1972 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1973 g_assert (!((gsize)vt & 7));
1976 vt->rank = class->rank;
1977 vt->domain = domain;
1979 mono_class_compute_gc_descriptor (class);
1981 * We can't use typed allocation in the non-root domains, since the
1982 * collector needs the GC descriptor stored in the vtable even after
1983 * the mempool containing the vtable is destroyed when the domain is
1984 * unloaded. An alternative might be to allocate vtables in the GC
1985 * heap, but this does not seem to work (it leads to crashes inside
1986 * libgc). If that approach is tried, two gc descriptors need to be
1987 * allocated for each class: one for the root domain, and one for all
1988 * other domains. The second descriptor should contain a bit for the
1989 * vtable field in MonoObject, since we can no longer assume the
1990 * vtable is reachable by other roots after the appdomain is unloaded.
1992 #ifdef HAVE_BOEHM_GC
1993 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1994 vt->gc_descr = GC_NO_DESCRIPTOR;
1997 vt->gc_descr = class->gc_descr;
1999 gc_bits = mono_gc_get_vtable_bits (class);
2000 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2002 vt->gc_bits = gc_bits;
2005 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2006 if (class->has_static_refs) {
2007 gpointer statics_gc_descr;
2009 gsize default_bitmap [4] = {0};
2012 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2013 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2014 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2015 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2016 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2017 if (bitmap != default_bitmap)
2020 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2022 vt->has_static_fields = TRUE;
2023 mono_stats.class_static_data_size += class_size;
2028 while ((field = mono_class_get_fields (class, &iter))) {
2029 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2031 if (mono_field_is_deleted (field))
2033 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2034 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2035 if (special_static != SPECIAL_STATIC_NONE) {
2036 guint32 size, offset;
2038 gsize default_bitmap [4] = {0};
2043 if (mono_type_is_reference (field->type)) {
2044 default_bitmap [0] = 1;
2046 bitmap = default_bitmap;
2047 } else if (mono_type_is_struct (field->type)) {
2048 fclass = mono_class_from_mono_type (field->type);
2049 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2050 numbits = max_set + 1;
2052 default_bitmap [0] = 0;
2054 bitmap = default_bitmap;
2056 size = mono_type_size (field->type, &align);
2057 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2058 if (!domain->special_static_fields)
2059 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2060 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2061 if (bitmap != default_bitmap)
2064 * This marks the field as special static to speed up the
2065 * checks in mono_field_static_get/set_value ().
2071 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2072 MonoClass *fklass = mono_class_from_mono_type (field->type);
2073 const char *data = mono_field_get_data (field);
2075 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2076 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2077 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2080 if (fklass->valuetype) {
2081 memcpy (t, data, mono_class_value_size (fklass, NULL));
2083 /* it's a pointer type: add check */
2084 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2091 vt->max_interface_id = class->max_interface_id;
2092 vt->interface_bitmap = class->interface_bitmap;
2094 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2095 // class->name, class->interface_offsets_count);
2097 if (! ARCH_USE_IMT) {
2098 /* initialize interface offsets */
2099 for (i = 0; i < class->interface_offsets_count; ++i) {
2100 int interface_id = class->interfaces_packed [i]->interface_id;
2101 int slot = class->interface_offsets_packed [i];
2102 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2106 /* Initialize vtable */
2107 if (callbacks.get_vtable_trampoline) {
2108 // This also covers the AOT case
2109 for (i = 0; i < class->vtable_size; ++i) {
2110 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2113 mono_class_setup_vtable (class);
2115 for (i = 0; i < class->vtable_size; ++i) {
2118 if ((cm = class->vtable [i]))
2119 vt->vtable [i] = arch_create_jit_trampoline (cm);
2123 if (ARCH_USE_IMT && imt_table_bytes) {
2124 /* Now that the vtable is full, we can actually fill up the IMT */
2125 if (callbacks.get_imt_trampoline) {
2126 /* lazy construction of the IMT entries enabled */
2127 for (i = 0; i < MONO_IMT_SIZE; ++i)
2128 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2130 build_imt (class, vt, domain, interface_offsets, NULL);
2135 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2136 * re-acquire them and check if another thread has created the vtable in the meantime.
2138 /* Special case System.MonoType to avoid infinite recursion */
2139 if (class != mono_defaults.monotype_class) {
2140 /*FIXME check for OOM*/
2141 vt->type = mono_type_get_object (domain, &class->byval_arg);
2142 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2143 /* This is unregistered in
2144 unregister_vtable_reflection_type() in
2146 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2149 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2151 /* class_vtable_array keeps an array of created vtables
2153 g_ptr_array_add (domain->class_vtable_array, vt);
2154 /* class->runtime_info is protected by the loader lock, both when
2155 * it it enlarged and when it is stored info.
2159 * Store the vtable in class->runtime_info.
2160 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2162 mono_memory_barrier ();
2164 old_info = class->runtime_info;
2165 if (old_info && old_info->max_domain >= domain->domain_id) {
2166 /* someone already created a large enough runtime info */
2167 old_info->domain_vtables [domain->domain_id] = vt;
2169 int new_size = domain->domain_id;
2171 new_size = MAX (new_size, old_info->max_domain);
2173 /* make the new size a power of two */
2175 while (new_size > i)
2178 /* this is a bounded memory retention issue: may want to
2179 * handle it differently when we'll have a rcu-like system.
2181 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2182 runtime_info->max_domain = new_size - 1;
2183 /* copy the stuff from the older info */
2185 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2187 runtime_info->domain_vtables [domain->domain_id] = vt;
2189 mono_memory_barrier ();
2190 class->runtime_info = runtime_info;
2193 if (class == mono_defaults.monotype_class) {
2194 /*FIXME check for OOM*/
2195 vt->type = mono_type_get_object (domain, &class->byval_arg);
2196 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2197 /* This is unregistered in
2198 unregister_vtable_reflection_type() in
2200 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2203 mono_domain_unlock (domain);
2204 mono_loader_unlock ();
2206 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2207 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2208 mono_raise_exception (mono_class_get_exception_for_failure (class));
2210 /* make sure the parent is initialized */
2211 /*FIXME shouldn't this fail the current type?*/
2213 mono_class_vtable_full (domain, class->parent, raise_on_error);
2218 #ifndef DISABLE_REMOTING
2220 * mono_class_proxy_vtable:
2221 * @domain: the application domain
2222 * @remove_class: the remote class
2224 * Creates a vtable for transparent proxies. It is basically
2225 * a copy of the real vtable of the class wrapped in @remote_class,
2226 * but all function pointers invoke the remoting functions, and
2227 * vtable->klass points to the transparent proxy class, and not to @class.
2230 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2233 MonoVTable *vt, *pvt;
2234 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2236 GSList *extra_interfaces = NULL;
2237 MonoClass *class = remote_class->proxy_class;
2238 gpointer *interface_offsets;
2241 size_t imt_table_bytes;
2243 #ifdef COMPRESSED_INTERFACE_BITMAP
2247 vt = mono_class_vtable (domain, class);
2248 g_assert (vt); /*FIXME property handle failure*/
2249 max_interface_id = vt->max_interface_id;
2251 /* Calculate vtable space for extra interfaces */
2252 for (j = 0; j < remote_class->interface_count; j++) {
2253 MonoClass* iclass = remote_class->interfaces[j];
2257 /*FIXME test for interfaces with variant generic arguments*/
2258 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2259 continue; /* interface implemented by the class */
2260 if (g_slist_find (extra_interfaces, iclass))
2263 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2265 method_count = mono_class_num_methods (iclass);
2267 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2268 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2270 for (i = 0; i < ifaces->len; ++i) {
2271 MonoClass *ic = g_ptr_array_index (ifaces, i);
2272 /*FIXME test for interfaces with variant generic arguments*/
2273 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2274 continue; /* interface implemented by the class */
2275 if (g_slist_find (extra_interfaces, ic))
2277 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2278 method_count += mono_class_num_methods (ic);
2280 g_ptr_array_free (ifaces, TRUE);
2283 extra_interface_vtsize += method_count * sizeof (gpointer);
2284 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2288 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2289 mono_stats.imt_number_of_tables++;
2290 mono_stats.imt_tables_size += imt_table_bytes;
2292 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2295 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2297 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2299 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2300 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2301 g_assert (!((gsize)pvt & 7));
2303 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2305 pvt->klass = mono_defaults.transparent_proxy_class;
2306 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2307 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2309 /* initialize vtable */
2310 mono_class_setup_vtable (class);
2311 for (i = 0; i < class->vtable_size; ++i) {
2314 if ((cm = class->vtable [i]))
2315 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2317 pvt->vtable [i] = NULL;
2320 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2321 /* create trampolines for abstract methods */
2322 for (k = class; k; k = k->parent) {
2324 gpointer iter = NULL;
2325 while ((m = mono_class_get_methods (k, &iter)))
2326 if (!pvt->vtable [m->slot])
2327 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2331 pvt->max_interface_id = max_interface_id;
2332 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2333 #ifdef COMPRESSED_INTERFACE_BITMAP
2334 bitmap = g_malloc0 (bsize);
2336 bitmap = mono_domain_alloc0 (domain, bsize);
2339 if (! ARCH_USE_IMT) {
2340 /* initialize interface offsets */
2341 for (i = 0; i < class->interface_offsets_count; ++i) {
2342 int interface_id = class->interfaces_packed [i]->interface_id;
2343 int slot = class->interface_offsets_packed [i];
2344 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2347 for (i = 0; i < class->interface_offsets_count; ++i) {
2348 int interface_id = class->interfaces_packed [i]->interface_id;
2349 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2352 if (extra_interfaces) {
2353 int slot = class->vtable_size;
2359 /* Create trampolines for the methods of the interfaces */
2360 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2361 interf = list_item->data;
2363 if (! ARCH_USE_IMT) {
2364 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2366 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2370 while ((cm = mono_class_get_methods (interf, &iter)))
2371 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2373 slot += mono_class_num_methods (interf);
2375 if (! ARCH_USE_IMT) {
2376 g_slist_free (extra_interfaces);
2381 /* Now that the vtable is full, we can actually fill up the IMT */
2382 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2383 if (extra_interfaces) {
2384 g_slist_free (extra_interfaces);
2388 #ifdef COMPRESSED_INTERFACE_BITMAP
2389 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2390 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2391 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2394 pvt->interface_bitmap = bitmap;
2399 #endif /* DISABLE_REMOTING */
2402 * mono_class_field_is_special_static:
2404 * Returns whether @field is a thread/context static field.
2407 mono_class_field_is_special_static (MonoClassField *field)
2409 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2411 if (mono_field_is_deleted (field))
2413 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2414 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2421 * mono_class_field_get_special_static_type:
2422 * @field: The MonoClassField describing the field.
2424 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2425 * SPECIAL_STATIC_NONE otherwise.
2428 mono_class_field_get_special_static_type (MonoClassField *field)
2430 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2431 return SPECIAL_STATIC_NONE;
2432 if (mono_field_is_deleted (field))
2433 return SPECIAL_STATIC_NONE;
2434 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2435 return field_is_special_static (field->parent, field);
2436 return SPECIAL_STATIC_NONE;
2440 * mono_class_has_special_static_fields:
2442 * Returns whenever @klass has any thread/context static fields.
2445 mono_class_has_special_static_fields (MonoClass *klass)
2447 MonoClassField *field;
2451 while ((field = mono_class_get_fields (klass, &iter))) {
2452 g_assert (field->parent == klass);
2453 if (mono_class_field_is_special_static (field))
2460 #ifndef DISABLE_REMOTING
2462 * create_remote_class_key:
2463 * Creates an array of pointers that can be used as a hash key for a remote class.
2464 * The first element of the array is the number of pointers.
2467 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2472 if (remote_class == NULL) {
2473 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2474 key = g_malloc (sizeof(gpointer) * 3);
2475 key [0] = GINT_TO_POINTER (2);
2476 key [1] = mono_defaults.marshalbyrefobject_class;
2477 key [2] = extra_class;
2479 key = g_malloc (sizeof(gpointer) * 2);
2480 key [0] = GINT_TO_POINTER (1);
2481 key [1] = extra_class;
2484 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2485 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2486 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2487 key [1] = remote_class->proxy_class;
2489 // Keep the list of interfaces sorted
2490 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2491 if (extra_class && remote_class->interfaces [i] > extra_class) {
2492 key [j++] = extra_class;
2495 key [j] = remote_class->interfaces [i];
2498 key [j] = extra_class;
2500 // Replace the old class. The interface list is the same
2501 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2502 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2503 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2504 for (i = 0; i < remote_class->interface_count; i++)
2505 key [2 + i] = remote_class->interfaces [i];
2513 * copy_remote_class_key:
2515 * Make a copy of KEY in the domain and return the copy.
2518 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2520 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2521 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2523 memcpy (mp_key, key, key_size);
2529 * mono_remote_class:
2530 * @domain: the application domain
2531 * @class_name: name of the remote class
2533 * Creates and initializes a MonoRemoteClass object for a remote type.
2535 * Can raise an exception on failure.
2538 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2541 MonoRemoteClass *rc;
2542 gpointer* key, *mp_key;
2545 key = create_remote_class_key (NULL, proxy_class);
2547 mono_domain_lock (domain);
2548 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2552 mono_domain_unlock (domain);
2556 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2557 if (!mono_error_ok (&error)) {
2559 mono_domain_unlock (domain);
2560 mono_error_raise_exception (&error);
2563 mp_key = copy_remote_class_key (domain, key);
2567 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2568 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2569 rc->interface_count = 1;
2570 rc->interfaces [0] = proxy_class;
2571 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2573 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2574 rc->interface_count = 0;
2575 rc->proxy_class = proxy_class;
2578 rc->default_vtable = NULL;
2579 rc->xdomain_vtable = NULL;
2580 rc->proxy_class_name = name;
2581 #ifndef DISABLE_PERFCOUNTERS
2582 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2585 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2587 mono_domain_unlock (domain);
2592 * clone_remote_class:
2593 * Creates a copy of the remote_class, adding the provided class or interface
2595 static MonoRemoteClass*
2596 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2598 MonoRemoteClass *rc;
2599 gpointer* key, *mp_key;
2601 key = create_remote_class_key (remote_class, extra_class);
2602 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2608 mp_key = copy_remote_class_key (domain, key);
2612 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2614 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2615 rc->proxy_class = remote_class->proxy_class;
2616 rc->interface_count = remote_class->interface_count + 1;
2618 // Keep the list of interfaces sorted, since the hash key of
2619 // the remote class depends on this
2620 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2621 if (remote_class->interfaces [i] > extra_class && i == j)
2622 rc->interfaces [j++] = extra_class;
2623 rc->interfaces [j] = remote_class->interfaces [i];
2626 rc->interfaces [j] = extra_class;
2628 // Replace the old class. The interface array is the same
2629 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2630 rc->proxy_class = extra_class;
2631 rc->interface_count = remote_class->interface_count;
2632 if (rc->interface_count > 0)
2633 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2636 rc->default_vtable = NULL;
2637 rc->xdomain_vtable = NULL;
2638 rc->proxy_class_name = remote_class->proxy_class_name;
2640 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2646 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2648 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2649 mono_domain_lock (domain);
2650 if (rp->target_domain_id != -1) {
2651 if (remote_class->xdomain_vtable == NULL)
2652 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2653 mono_domain_unlock (domain);
2654 mono_loader_unlock ();
2655 return remote_class->xdomain_vtable;
2657 if (remote_class->default_vtable == NULL) {
2660 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2661 klass = mono_class_from_mono_type (type);
2663 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)))
2664 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2667 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2672 return remote_class->default_vtable;
2676 * mono_upgrade_remote_class:
2677 * @domain: the application domain
2678 * @tproxy: the proxy whose remote class has to be upgraded.
2679 * @klass: class to which the remote class can be casted.
2681 * Updates the vtable of the remote class by adding the necessary method slots
2682 * and interface offsets so it can be safely casted to klass. klass can be a
2683 * class or an interface.
2686 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2688 MonoTransparentProxy *tproxy;
2689 MonoRemoteClass *remote_class;
2690 gboolean redo_vtable;
2692 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2693 mono_domain_lock (domain);
2695 tproxy = (MonoTransparentProxy*) proxy_object;
2696 remote_class = tproxy->remote_class;
2698 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2701 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2702 if (remote_class->interfaces [i] == klass)
2703 redo_vtable = FALSE;
2706 redo_vtable = (remote_class->proxy_class != klass);
2710 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2711 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2714 mono_domain_unlock (domain);
2715 mono_loader_unlock ();
2717 #endif /* DISABLE_REMOTING */
2721 * mono_object_get_virtual_method:
2722 * @obj: object to operate on.
2725 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2726 * the instance of a callvirt of method.
2729 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2732 MonoMethod **vtable;
2733 gboolean is_proxy = FALSE;
2734 MonoMethod *res = NULL;
2736 klass = mono_object_class (obj);
2737 #ifndef DISABLE_REMOTING
2738 if (klass == mono_defaults.transparent_proxy_class) {
2739 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2744 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2747 mono_class_setup_vtable (klass);
2748 vtable = klass->vtable;
2750 if (method->slot == -1) {
2751 /* method->slot might not be set for instances of generic methods */
2752 if (method->is_inflated) {
2753 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2754 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2757 g_assert_not_reached ();
2761 /* check method->slot is a valid index: perform isinstance? */
2762 if (method->slot != -1) {
2763 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2765 gboolean variance_used = FALSE;
2766 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2767 g_assert (iface_offset > 0);
2768 res = vtable [iface_offset + method->slot];
2771 res = vtable [method->slot];
2775 #ifndef DISABLE_REMOTING
2777 /* It may be an interface, abstract class method or generic method */
2778 if (!res || mono_method_signature (res)->generic_param_count)
2781 /* generic methods demand invoke_with_check */
2782 if (mono_method_signature (res)->generic_param_count)
2783 res = mono_marshal_get_remoting_invoke_with_check (res);
2786 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2787 res = mono_cominterop_get_invoke (res);
2790 res = mono_marshal_get_remoting_invoke (res);
2795 if (method->is_inflated) {
2797 /* Have to inflate the result */
2798 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2799 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2809 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2811 g_error ("runtime invoke called on uninitialized runtime");
2815 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2818 * mono_runtime_invoke:
2819 * @method: method to invoke
2820 * @obJ: object instance
2821 * @params: arguments to the method
2822 * @exc: exception information.
2824 * Invokes the method represented by @method on the object @obj.
2826 * obj is the 'this' pointer, it should be NULL for static
2827 * methods, a MonoObject* for object instances and a pointer to
2828 * the value type for value types.
2830 * The params array contains the arguments to the method with the
2831 * same convention: MonoObject* pointers for object instances and
2832 * pointers to the value type otherwise.
2834 * From unmanaged code you'll usually use the
2835 * mono_runtime_invoke() variant.
2837 * Note that this function doesn't handle virtual methods for
2838 * you, it will exec the exact method you pass: we still need to
2839 * expose a function to lookup the derived class implementation
2840 * of a virtual method (there are examples of this in the code,
2843 * You can pass NULL as the exc argument if you don't want to
2844 * catch exceptions, otherwise, *exc will be set to the exception
2845 * thrown, if any. if an exception is thrown, you can't use the
2846 * MonoObject* result from the function.
2848 * If the method returns a value type, it is boxed in an object
2852 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2856 if (mono_runtime_get_no_exec ())
2857 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2859 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2860 mono_profiler_method_start_invoke (method);
2862 result = default_mono_runtime_invoke (method, obj, params, exc);
2864 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2865 mono_profiler_method_end_invoke (method);
2871 * mono_method_get_unmanaged_thunk:
2872 * @method: method to generate a thunk for.
2874 * Returns an unmanaged->managed thunk that can be used to call
2875 * a managed method directly from C.
2877 * The thunk's C signature closely matches the managed signature:
2879 * C#: public bool Equals (object obj);
2880 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2881 * MonoObject*, MonoException**);
2883 * The 1st ("this") parameter must not be used with static methods:
2885 * C#: public static bool ReferenceEquals (object a, object b);
2886 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2889 * The last argument must be a non-null pointer of a MonoException* pointer.
2890 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2891 * exception has been thrown in managed code. Otherwise it will point
2892 * to the MonoException* caught by the thunk. In this case, the result of
2893 * the thunk is undefined:
2895 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2896 * MonoException *ex = NULL;
2897 * Equals func = mono_method_get_unmanaged_thunk (method);
2898 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2900 * // handle exception
2903 * The calling convention of the thunk matches the platform's default
2904 * convention. This means that under Windows, C declarations must
2905 * contain the __stdcall attribute:
2907 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2908 * MonoObject*, MonoException**);
2912 * Value type arguments and return values are treated as they were objects:
2914 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2915 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2917 * Arguments must be properly boxed upon trunk's invocation, while return
2918 * values must be unboxed.
2921 mono_method_get_unmanaged_thunk (MonoMethod *method)
2923 method = mono_marshal_get_thunk_invoke_wrapper (method);
2924 return mono_compile_method (method);
2928 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2932 /* object fields cannot be byref, so we don't need a
2934 gpointer *p = (gpointer*)dest;
2941 case MONO_TYPE_BOOLEAN:
2943 case MONO_TYPE_U1: {
2944 guint8 *p = (guint8*)dest;
2945 *p = value ? *(guint8*)value : 0;
2950 case MONO_TYPE_CHAR: {
2951 guint16 *p = (guint16*)dest;
2952 *p = value ? *(guint16*)value : 0;
2955 #if SIZEOF_VOID_P == 4
2960 case MONO_TYPE_U4: {
2961 gint32 *p = (gint32*)dest;
2962 *p = value ? *(gint32*)value : 0;
2965 #if SIZEOF_VOID_P == 8
2970 case MONO_TYPE_U8: {
2971 gint64 *p = (gint64*)dest;
2972 *p = value ? *(gint64*)value : 0;
2975 case MONO_TYPE_R4: {
2976 float *p = (float*)dest;
2977 *p = value ? *(float*)value : 0;
2980 case MONO_TYPE_R8: {
2981 double *p = (double*)dest;
2982 *p = value ? *(double*)value : 0;
2985 case MONO_TYPE_STRING:
2986 case MONO_TYPE_SZARRAY:
2987 case MONO_TYPE_CLASS:
2988 case MONO_TYPE_OBJECT:
2989 case MONO_TYPE_ARRAY:
2990 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2992 case MONO_TYPE_FNPTR:
2993 case MONO_TYPE_PTR: {
2994 gpointer *p = (gpointer*)dest;
2995 *p = deref_pointer? *(gpointer*)value: value;
2998 case MONO_TYPE_VALUETYPE:
2999 /* note that 't' and 'type->type' can be different */
3000 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3001 t = mono_class_enum_basetype (type->data.klass)->type;
3004 MonoClass *class = mono_class_from_mono_type (type);
3005 int size = mono_class_value_size (class, NULL);
3007 mono_gc_bzero_atomic (dest, size);
3009 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3012 case MONO_TYPE_GENERICINST:
3013 t = type->data.generic_class->container_class->byval_arg.type;
3016 g_error ("got type %x", type->type);
3021 * mono_field_set_value:
3022 * @obj: Instance object
3023 * @field: MonoClassField describing the field to set
3024 * @value: The value to be set
3026 * Sets the value of the field described by @field in the object instance @obj
3027 * to the value passed in @value. This method should only be used for instance
3028 * fields. For static fields, use mono_field_static_set_value.
3030 * The value must be on the native format of the field type.
3033 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3037 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3039 dest = (char*)obj + field->offset;
3040 set_value (field->type, dest, value, FALSE);
3044 * mono_field_static_set_value:
3045 * @field: MonoClassField describing the field to set
3046 * @value: The value to be set
3048 * Sets the value of the static field described by @field
3049 * to the value passed in @value.
3051 * The value must be on the native format of the field type.
3054 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3058 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3059 /* you cant set a constant! */
3060 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3062 if (field->offset == -1) {
3063 /* Special static */
3066 mono_domain_lock (vt->domain);
3067 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3068 mono_domain_unlock (vt->domain);
3069 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3071 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3073 set_value (field->type, dest, value, FALSE);
3077 * mono_vtable_get_static_field_data:
3079 * Internal use function: return a pointer to the memory holding the static fields
3080 * for a class or NULL if there are no static fields.
3081 * This is exported only for use by the debugger.
3084 mono_vtable_get_static_field_data (MonoVTable *vt)
3086 if (!vt->has_static_fields)
3088 return vt->vtable [vt->klass->vtable_size];
3092 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3096 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3097 if (field->offset == -1) {
3098 /* Special static */
3101 mono_domain_lock (vt->domain);
3102 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3103 mono_domain_unlock (vt->domain);
3104 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3106 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3109 src = (guint8*)obj + field->offset;
3116 * mono_field_get_value:
3117 * @obj: Object instance
3118 * @field: MonoClassField describing the field to fetch information from
3119 * @value: pointer to the location where the value will be stored
3121 * Use this routine to get the value of the field @field in the object
3124 * The pointer provided by value must be of the field type, for reference
3125 * types this is a MonoObject*, for value types its the actual pointer to
3130 * mono_field_get_value (obj, int_field, &i);
3133 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3139 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3141 src = (char*)obj + field->offset;
3142 set_value (field->type, value, src, TRUE);
3146 * mono_field_get_value_object:
3147 * @domain: domain where the object will be created (if boxing)
3148 * @field: MonoClassField describing the field to fetch information from
3149 * @obj: The object instance for the field.
3151 * Returns: a new MonoObject with the value from the given field. If the
3152 * field represents a value type, the value is boxed.
3156 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3160 MonoVTable *vtable = NULL;
3162 gboolean is_static = FALSE;
3163 gboolean is_ref = FALSE;
3164 gboolean is_literal = FALSE;
3165 gboolean is_ptr = FALSE;
3167 MonoType *type = mono_field_get_type_checked (field, &error);
3169 if (!mono_error_ok (&error))
3170 mono_error_raise_exception (&error);
3172 switch (type->type) {
3173 case MONO_TYPE_STRING:
3174 case MONO_TYPE_OBJECT:
3175 case MONO_TYPE_CLASS:
3176 case MONO_TYPE_ARRAY:
3177 case MONO_TYPE_SZARRAY:
3182 case MONO_TYPE_BOOLEAN:
3185 case MONO_TYPE_CHAR:
3194 case MONO_TYPE_VALUETYPE:
3195 is_ref = type->byref;
3197 case MONO_TYPE_GENERICINST:
3198 is_ref = !mono_type_generic_inst_is_valuetype (type);
3204 g_error ("type 0x%x not handled in "
3205 "mono_field_get_value_object", type->type);
3209 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3212 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3216 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3217 if (!vtable->initialized)
3218 mono_runtime_class_init (vtable);
3226 get_default_field_value (domain, field, &o);
3227 } else if (is_static) {
3228 mono_field_static_get_value (vtable, field, &o);
3230 mono_field_get_value (obj, field, &o);
3236 static MonoMethod *m;
3242 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3243 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3249 get_default_field_value (domain, field, v);
3250 } else if (is_static) {
3251 mono_field_static_get_value (vtable, field, v);
3253 mono_field_get_value (obj, field, v);
3256 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3257 args [0] = ptr ? *ptr : NULL;
3258 args [1] = mono_type_get_object (mono_domain_get (), type);
3260 return mono_runtime_invoke (m, NULL, args, NULL);
3263 /* boxed value type */
3264 klass = mono_class_from_mono_type (type);
3266 if (mono_class_is_nullable (klass))
3267 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3269 o = mono_object_new (domain, klass);
3270 v = ((gchar *) o) + sizeof (MonoObject);
3273 get_default_field_value (domain, field, v);
3274 } else if (is_static) {
3275 mono_field_static_get_value (vtable, field, v);
3277 mono_field_get_value (obj, field, v);
3284 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3287 const char *p = blob;
3288 mono_metadata_decode_blob_size (p, &p);
3291 case MONO_TYPE_BOOLEAN:
3294 *(guint8 *) value = *p;
3296 case MONO_TYPE_CHAR:
3299 *(guint16*) value = read16 (p);
3303 *(guint32*) value = read32 (p);
3307 *(guint64*) value = read64 (p);
3310 readr4 (p, (float*) value);
3313 readr8 (p, (double*) value);
3315 case MONO_TYPE_STRING:
3316 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3318 case MONO_TYPE_CLASS:
3319 *(gpointer*) value = NULL;
3323 g_warning ("type 0x%02x should not be in constant table", type);
3329 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3331 MonoTypeEnum def_type;
3334 data = mono_class_get_field_default_value (field, &def_type);
3335 mono_get_constant_value_from_blob (domain, def_type, data, value);
3339 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3343 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3345 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3346 get_default_field_value (vt->domain, field, value);
3350 if (field->offset == -1) {
3351 /* Special static */
3352 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3353 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3355 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3357 set_value (field->type, value, src, TRUE);
3361 * mono_field_static_get_value:
3362 * @vt: vtable to the object
3363 * @field: MonoClassField describing the field to fetch information from
3364 * @value: where the value is returned
3366 * Use this routine to get the value of the static field @field value.
3368 * The pointer provided by value must be of the field type, for reference
3369 * types this is a MonoObject*, for value types its the actual pointer to
3374 * mono_field_static_get_value (vt, int_field, &i);
3377 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3379 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3383 * mono_property_set_value:
3384 * @prop: MonoProperty to set
3385 * @obj: instance object on which to act
3386 * @params: parameters to pass to the propery
3387 * @exc: optional exception
3389 * Invokes the property's set method with the given arguments on the
3390 * object instance obj (or NULL for static properties).
3392 * You can pass NULL as the exc argument if you don't want to
3393 * catch exceptions, otherwise, *exc will be set to the exception
3394 * thrown, if any. if an exception is thrown, you can't use the
3395 * MonoObject* result from the function.
3398 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3400 default_mono_runtime_invoke (prop->set, obj, params, exc);
3404 * mono_property_get_value:
3405 * @prop: MonoProperty to fetch
3406 * @obj: instance object on which to act
3407 * @params: parameters to pass to the propery
3408 * @exc: optional exception
3410 * Invokes the property's get method with the given arguments on the
3411 * object instance obj (or NULL for static properties).
3413 * You can pass NULL as the exc argument if you don't want to
3414 * catch exceptions, otherwise, *exc will be set to the exception
3415 * thrown, if any. if an exception is thrown, you can't use the
3416 * MonoObject* result from the function.
3418 * Returns: the value from invoking the get method on the property.
3421 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3423 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3427 * mono_nullable_init:
3428 * @buf: The nullable structure to initialize.
3429 * @value: the value to initialize from
3430 * @klass: the type for the object
3432 * Initialize the nullable structure pointed to by @buf from @value which
3433 * should be a boxed value type. The size of @buf should be able to hold
3434 * as much data as the @klass->instance_size (which is the number of bytes
3435 * that will be copies).
3437 * Since Nullables have variable structure, we can not define a C
3438 * structure for them.
3441 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3443 MonoClass *param_class = klass->cast_class;
3445 mono_class_setup_fields_locking (klass);
3446 g_assert (klass->fields_inited);
3448 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3449 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3451 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3453 if (param_class->has_references)
3454 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3456 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3458 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3463 * mono_nullable_box:
3464 * @buf: The buffer representing the data to be boxed
3465 * @klass: the type to box it as.
3467 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3471 mono_nullable_box (guint8 *buf, MonoClass *klass)
3473 MonoClass *param_class = klass->cast_class;
3475 mono_class_setup_fields_locking (klass);
3476 g_assert (klass->fields_inited);
3478 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3479 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3481 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3482 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3483 if (param_class->has_references)
3484 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3486 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3494 * mono_get_delegate_invoke:
3495 * @klass: The delegate class
3497 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3500 mono_get_delegate_invoke (MonoClass *klass)
3504 /* This is called at runtime, so avoid the slower search in metadata */
3505 mono_class_setup_methods (klass);
3506 if (klass->exception_type)
3508 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3513 * mono_get_delegate_begin_invoke:
3514 * @klass: The delegate class
3516 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3519 mono_get_delegate_begin_invoke (MonoClass *klass)
3523 /* This is called at runtime, so avoid the slower search in metadata */
3524 mono_class_setup_methods (klass);
3525 if (klass->exception_type)
3527 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3532 * mono_get_delegate_end_invoke:
3533 * @klass: The delegate class
3535 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3538 mono_get_delegate_end_invoke (MonoClass *klass)
3542 /* This is called at runtime, so avoid the slower search in metadata */
3543 mono_class_setup_methods (klass);
3544 if (klass->exception_type)
3546 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3551 * mono_runtime_delegate_invoke:
3552 * @delegate: pointer to a delegate object.
3553 * @params: parameters for the delegate.
3554 * @exc: Pointer to the exception result.
3556 * Invokes the delegate method @delegate with the parameters provided.
3558 * You can pass NULL as the exc argument if you don't want to
3559 * catch exceptions, otherwise, *exc will be set to the exception
3560 * thrown, if any. if an exception is thrown, you can't use the
3561 * MonoObject* result from the function.
3564 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3567 MonoClass *klass = delegate->vtable->klass;
3569 im = mono_get_delegate_invoke (klass);
3571 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3573 return mono_runtime_invoke (im, delegate, params, exc);
3576 static char **main_args = NULL;
3577 static int num_main_args = 0;
3580 * mono_runtime_get_main_args:
3582 * Returns: a MonoArray with the arguments passed to the main program
3585 mono_runtime_get_main_args (void)
3589 MonoDomain *domain = mono_domain_get ();
3591 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3593 for (i = 0; i < num_main_args; ++i)
3594 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3600 free_main_args (void)
3604 for (i = 0; i < num_main_args; ++i)
3605 g_free (main_args [i]);
3612 * mono_runtime_set_main_args:
3613 * @argc: number of arguments from the command line
3614 * @argv: array of strings from the command line
3616 * Set the command line arguments from an embedding application that doesn't otherwise call
3617 * mono_runtime_run_main ().
3620 mono_runtime_set_main_args (int argc, char* argv[])
3625 main_args = g_new0 (char*, argc);
3626 num_main_args = argc;
3628 for (i = 0; i < argc; ++i) {
3631 utf8_arg = mono_utf8_from_external (argv[i]);
3632 if (utf8_arg == NULL) {
3633 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3634 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3638 main_args [i] = utf8_arg;
3645 * mono_runtime_run_main:
3646 * @method: the method to start the application with (usually Main)
3647 * @argc: number of arguments from the command line
3648 * @argv: array of strings from the command line
3649 * @exc: excetption results
3651 * Execute a standard Main() method (argc/argv contains the
3652 * executable name). This method also sets the command line argument value
3653 * needed by System.Environment.
3658 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3662 MonoArray *args = NULL;
3663 MonoDomain *domain = mono_domain_get ();
3664 gchar *utf8_fullpath;
3665 MonoMethodSignature *sig;
3667 g_assert (method != NULL);
3669 mono_thread_set_main (mono_thread_current ());
3671 main_args = g_new0 (char*, argc);
3672 num_main_args = argc;
3674 if (!g_path_is_absolute (argv [0])) {
3675 gchar *basename = g_path_get_basename (argv [0]);
3676 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3680 utf8_fullpath = mono_utf8_from_external (fullpath);
3681 if(utf8_fullpath == NULL) {
3682 /* Printing the arg text will cause glib to
3683 * whinge about "Invalid UTF-8", but at least
3684 * its relevant, and shows the problem text
3687 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3688 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3695 utf8_fullpath = mono_utf8_from_external (argv[0]);
3696 if(utf8_fullpath == NULL) {
3697 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3698 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3703 main_args [0] = utf8_fullpath;
3705 for (i = 1; i < argc; ++i) {
3708 utf8_arg=mono_utf8_from_external (argv[i]);
3709 if(utf8_arg==NULL) {
3710 /* Ditto the comment about Invalid UTF-8 here */
3711 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3712 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3716 main_args [i] = utf8_arg;
3721 sig = mono_method_signature (method);
3723 g_print ("Unable to load Main method.\n");
3727 if (sig->param_count) {
3728 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3729 for (i = 0; i < argc; ++i) {
3730 /* The encodings should all work, given that
3731 * we've checked all these args for the
3734 gchar *str = mono_utf8_from_external (argv [i]);
3735 MonoString *arg = mono_string_new (domain, str);
3736 mono_array_setref (args, i, arg);
3740 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3743 mono_assembly_set_main (method->klass->image->assembly);
3745 return mono_runtime_exec_main (method, args, exc);
3749 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3751 static MonoMethod *serialize_method;
3756 if (!serialize_method) {
3757 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3758 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3761 if (!serialize_method) {
3766 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3770 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3778 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3780 static MonoMethod *deserialize_method;
3785 if (!deserialize_method) {
3786 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3787 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3789 if (!deserialize_method) {
3796 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3803 #ifndef DISABLE_REMOTING
3805 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3807 static MonoMethod *get_proxy_method;
3809 MonoDomain *domain = mono_domain_get ();
3810 MonoRealProxy *real_proxy;
3811 MonoReflectionType *reflection_type;
3812 MonoTransparentProxy *transparent_proxy;
3814 if (!get_proxy_method)
3815 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3817 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3819 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3820 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3822 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3823 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3826 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3830 return (MonoObject*) transparent_proxy;
3832 #endif /* DISABLE_REMOTING */
3835 * mono_object_xdomain_representation
3837 * @target_domain: a domain
3838 * @exc: pointer to a MonoObject*
3840 * Creates a representation of obj in the domain target_domain. This
3841 * is either a copy of obj arrived through via serialization and
3842 * deserialization or a proxy, depending on whether the object is
3843 * serializable or marshal by ref. obj must not be in target_domain.
3845 * If the object cannot be represented in target_domain, NULL is
3846 * returned and *exc is set to an appropriate exception.
3849 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3851 MonoObject *deserialized = NULL;
3852 gboolean failure = FALSE;
3856 #ifndef DISABLE_REMOTING
3857 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3858 deserialized = make_transparent_proxy (obj, &failure, exc);
3863 MonoDomain *domain = mono_domain_get ();
3864 MonoObject *serialized;
3866 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3867 serialized = serialize_object (obj, &failure, exc);
3868 mono_domain_set_internal_with_options (target_domain, FALSE);
3870 deserialized = deserialize_object (serialized, &failure, exc);
3871 if (domain != target_domain)
3872 mono_domain_set_internal_with_options (domain, FALSE);
3875 return deserialized;
3878 /* Used in call_unhandled_exception_delegate */
3880 create_unhandled_exception_eventargs (MonoObject *exc)
3884 MonoMethod *method = NULL;
3885 MonoBoolean is_terminating = TRUE;
3888 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3891 mono_class_init (klass);
3893 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3894 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3898 args [1] = &is_terminating;
3900 obj = mono_object_new (mono_domain_get (), klass);
3901 mono_runtime_invoke (method, obj, args, NULL);
3906 /* Used in mono_unhandled_exception */
3908 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3909 MonoObject *e = NULL;
3911 MonoDomain *current_domain = mono_domain_get ();
3913 if (domain != current_domain)
3914 mono_domain_set_internal_with_options (domain, FALSE);
3916 g_assert (domain == mono_object_domain (domain->domain));
3918 if (mono_object_domain (exc) != domain) {
3919 MonoObject *serialization_exc;
3921 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3923 if (serialization_exc) {
3925 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3928 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3929 "System.Runtime.Serialization", "SerializationException",
3930 "Could not serialize unhandled exception.");
3934 g_assert (mono_object_domain (exc) == domain);
3936 pa [0] = domain->domain;
3937 pa [1] = create_unhandled_exception_eventargs (exc);
3938 mono_runtime_delegate_invoke (delegate, pa, &e);
3940 if (domain != current_domain)
3941 mono_domain_set_internal_with_options (current_domain, FALSE);
3945 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3946 if (!mono_error_ok (&error)) {
3947 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3948 mono_error_cleanup (&error);
3950 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3956 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3959 * mono_runtime_unhandled_exception_policy_set:
3960 * @policy: the new policy
3962 * This is a VM internal routine.
3964 * Sets the runtime policy for handling unhandled exceptions.
3967 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3968 runtime_unhandled_exception_policy = policy;
3972 * mono_runtime_unhandled_exception_policy_get:
3974 * This is a VM internal routine.
3976 * Gets the runtime policy for handling unhandled exceptions.
3978 MonoRuntimeUnhandledExceptionPolicy
3979 mono_runtime_unhandled_exception_policy_get (void) {
3980 return runtime_unhandled_exception_policy;
3984 * mono_unhandled_exception:
3985 * @exc: exception thrown
3987 * This is a VM internal routine.
3989 * We call this function when we detect an unhandled exception
3990 * in the default domain.
3992 * It invokes the * UnhandledException event in AppDomain or prints
3993 * a warning to the console
3996 mono_unhandled_exception (MonoObject *exc)
3998 MonoDomain *current_domain = mono_domain_get ();
3999 MonoDomain *root_domain = mono_get_root_domain ();
4000 MonoClassField *field;
4001 MonoObject *current_appdomain_delegate;
4002 MonoObject *root_appdomain_delegate;
4004 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
4005 "UnhandledException");
4008 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4009 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4010 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4011 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4012 if (current_domain != root_domain) {
4013 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4015 current_appdomain_delegate = NULL;
4018 /* set exitcode only if we will abort the process */
4019 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4021 mono_environment_exitcode_set (1);
4022 mono_print_unhandled_exception (exc);
4024 if (root_appdomain_delegate) {
4025 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4027 if (current_appdomain_delegate) {
4028 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4035 * mono_runtime_exec_managed_code:
4036 * @domain: Application domain
4037 * @main_func: function to invoke from the execution thread
4038 * @main_args: parameter to the main_func
4040 * Launch a new thread to execute a function
4042 * main_func is called back from the thread with main_args as the
4043 * parameter. The callback function is expected to start Main()
4044 * eventually. This function then waits for all managed threads to
4046 * It is not necesseray anymore to execute managed code in a subthread,
4047 * so this function should not be used anymore by default: just
4048 * execute the code and then call mono_thread_manage ().
4051 mono_runtime_exec_managed_code (MonoDomain *domain,
4052 MonoMainThreadFunc main_func,
4055 mono_thread_create (domain, main_func, main_args);
4057 mono_thread_manage ();
4061 * Execute a standard Main() method (args doesn't contain the
4065 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4070 MonoCustomAttrInfo* cinfo;
4071 gboolean has_stathread_attribute;
4072 MonoInternalThread* thread = mono_thread_internal_current ();
4078 domain = mono_object_domain (args);
4079 if (!domain->entry_assembly) {
4081 MonoAssembly *assembly;
4083 assembly = method->klass->image->assembly;
4084 domain->entry_assembly = assembly;
4085 /* Domains created from another domain already have application_base and configuration_file set */
4086 if (domain->setup->application_base == NULL) {
4087 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4090 if (domain->setup->configuration_file == NULL) {
4091 str = g_strconcat (assembly->image->name, ".config", NULL);
4092 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4094 mono_set_private_bin_path_from_config (domain);
4098 cinfo = mono_custom_attrs_from_method (method);
4100 static MonoClass *stathread_attribute = NULL;
4101 if (!stathread_attribute)
4102 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4103 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4105 mono_custom_attrs_free (cinfo);
4107 has_stathread_attribute = FALSE;
4109 if (has_stathread_attribute) {
4110 thread->apartment_state = ThreadApartmentState_STA;
4112 thread->apartment_state = ThreadApartmentState_MTA;
4114 mono_thread_init_apartment_state ();
4116 /* FIXME: check signature of method */
4117 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4119 res = mono_runtime_invoke (method, NULL, pa, exc);
4121 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4125 mono_environment_exitcode_set (rval);
4127 mono_runtime_invoke (method, NULL, pa, exc);
4131 /* If the return type of Main is void, only
4132 * set the exitcode if an exception was thrown
4133 * (we don't want to blow away an
4134 * explicitly-set exit code)
4137 mono_environment_exitcode_set (rval);
4145 * mono_install_runtime_invoke:
4146 * @func: Function to install
4148 * This is a VM internal routine
4151 mono_install_runtime_invoke (MonoInvokeFunc func)
4153 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4158 * mono_runtime_invoke_array:
4159 * @method: method to invoke
4160 * @obJ: object instance
4161 * @params: arguments to the method
4162 * @exc: exception information.
4164 * Invokes the method represented by @method on the object @obj.
4166 * obj is the 'this' pointer, it should be NULL for static
4167 * methods, a MonoObject* for object instances and a pointer to
4168 * the value type for value types.
4170 * The params array contains the arguments to the method with the
4171 * same convention: MonoObject* pointers for object instances and
4172 * pointers to the value type otherwise. The _invoke_array
4173 * variant takes a C# object[] as the params argument (MonoArray
4174 * *params): in this case the value types are boxed inside the
4175 * respective reference representation.
4177 * From unmanaged code you'll usually use the
4178 * mono_runtime_invoke() variant.
4180 * Note that this function doesn't handle virtual methods for
4181 * you, it will exec the exact method you pass: we still need to
4182 * expose a function to lookup the derived class implementation
4183 * of a virtual method (there are examples of this in the code,
4186 * You can pass NULL as the exc argument if you don't want to
4187 * catch exceptions, otherwise, *exc will be set to the exception
4188 * thrown, if any. if an exception is thrown, you can't use the
4189 * MonoObject* result from the function.
4191 * If the method returns a value type, it is boxed in an object
4195 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4198 MonoMethodSignature *sig = mono_method_signature (method);
4199 gpointer *pa = NULL;
4202 gboolean has_byref_nullables = FALSE;
4204 if (NULL != params) {
4205 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4206 for (i = 0; i < mono_array_length (params); i++) {
4207 MonoType *t = sig->params [i];
4213 case MONO_TYPE_BOOLEAN:
4216 case MONO_TYPE_CHAR:
4225 case MONO_TYPE_VALUETYPE:
4226 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4227 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4228 pa [i] = mono_array_get (params, MonoObject*, i);
4230 has_byref_nullables = TRUE;
4232 /* MS seems to create the objects if a null is passed in */
4233 if (!mono_array_get (params, MonoObject*, i))
4234 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4238 * We can't pass the unboxed vtype byref to the callee, since
4239 * that would mean the callee would be able to modify boxed
4240 * primitive types. So we (and MS) make a copy of the boxed
4241 * object, pass that to the callee, and replace the original
4242 * boxed object in the arg array with the copy.
4244 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4245 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4246 mono_array_setref (params, i, copy);
4249 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4252 case MONO_TYPE_STRING:
4253 case MONO_TYPE_OBJECT:
4254 case MONO_TYPE_CLASS:
4255 case MONO_TYPE_ARRAY:
4256 case MONO_TYPE_SZARRAY:
4258 pa [i] = mono_array_addr (params, MonoObject*, i);
4259 // FIXME: I need to check this code path
4261 pa [i] = mono_array_get (params, MonoObject*, i);
4263 case MONO_TYPE_GENERICINST:
4265 t = &t->data.generic_class->container_class->this_arg;
4267 t = &t->data.generic_class->container_class->byval_arg;
4269 case MONO_TYPE_PTR: {
4272 /* The argument should be an IntPtr */
4273 arg = mono_array_get (params, MonoObject*, i);
4277 g_assert (arg->vtable->klass == mono_defaults.int_class);
4278 pa [i] = ((MonoIntPtr*)arg)->m_value;
4283 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4288 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4291 if (mono_class_is_nullable (method->klass)) {
4292 /* Need to create a boxed vtype instead */
4298 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4302 obj = mono_object_new (mono_domain_get (), method->klass);
4303 g_assert (obj); /*maybe we should raise a TLE instead?*/
4304 #ifndef DISABLE_REMOTING
4305 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4306 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4309 if (method->klass->valuetype)
4310 o = mono_object_unbox (obj);
4313 } else if (method->klass->valuetype) {
4314 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4317 mono_runtime_invoke (method, o, pa, exc);
4320 if (mono_class_is_nullable (method->klass)) {
4321 MonoObject *nullable;
4323 /* Convert the unboxed vtype into a Nullable structure */
4324 nullable = mono_object_new (mono_domain_get (), method->klass);
4326 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4327 obj = mono_object_unbox (nullable);
4330 /* obj must be already unboxed if needed */
4331 res = mono_runtime_invoke (method, obj, pa, exc);
4333 if (sig->ret->type == MONO_TYPE_PTR) {
4334 MonoClass *pointer_class;
4335 static MonoMethod *box_method;
4337 MonoObject *box_exc;
4340 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4341 * convert it to a Pointer object.
4343 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4345 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4347 g_assert (res->vtable->klass == mono_defaults.int_class);
4348 box_args [0] = ((MonoIntPtr*)res)->m_value;
4349 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4350 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4351 g_assert (!box_exc);
4354 if (has_byref_nullables) {
4356 * The runtime invoke wrapper already converted byref nullables back,
4357 * and stored them in pa, we just need to copy them back to the
4360 for (i = 0; i < mono_array_length (params); i++) {
4361 MonoType *t = sig->params [i];
4363 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4364 mono_array_setref (params, i, pa [i]);
4373 arith_overflow (void)
4375 mono_raise_exception (mono_get_exception_overflow ());
4379 * mono_object_allocate:
4380 * @size: number of bytes to allocate
4382 * This is a very simplistic routine until we have our GC-aware
4385 * Returns: an allocated object of size @size, or NULL on failure.
4387 static inline void *
4388 mono_object_allocate (size_t size, MonoVTable *vtable)
4391 ALLOC_OBJECT (o, vtable, size);
4397 * mono_object_allocate_ptrfree:
4398 * @size: number of bytes to allocate
4400 * Note that the memory allocated is not zeroed.
4401 * Returns: an allocated object of size @size, or NULL on failure.
4403 static inline void *
4404 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4407 ALLOC_PTRFREE (o, vtable, size);
4411 static inline void *
4412 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4415 ALLOC_TYPED (o, size, vtable);
4422 * @klass: the class of the object that we want to create
4424 * Returns: a newly created object whose definition is
4425 * looked up using @klass. This will not invoke any constructors,
4426 * so the consumer of this routine has to invoke any constructors on
4427 * its own to initialize the object.
4429 * It returns NULL on failure.
4432 mono_object_new (MonoDomain *domain, MonoClass *klass)
4436 vtable = mono_class_vtable (domain, klass);
4439 return mono_object_new_specific (vtable);
4443 * mono_object_new_pinned:
4445 * Same as mono_object_new, but the returned object will be pinned.
4446 * For SGEN, these objects will only be freed at appdomain unload.
4449 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4453 vtable = mono_class_vtable (domain, klass);
4458 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4460 return mono_object_new_specific (vtable);
4465 * mono_object_new_specific:
4466 * @vtable: the vtable of the object that we want to create
4468 * Returns: A newly created object with class and domain specified
4472 mono_object_new_specific (MonoVTable *vtable)
4476 /* check for is_com_object for COM Interop */
4477 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4480 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4483 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4486 mono_class_init (klass);
4488 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4490 vtable->domain->create_proxy_for_type_method = im;
4493 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4495 o = mono_runtime_invoke (im, NULL, pa, NULL);
4496 if (o != NULL) return o;
4499 return mono_object_new_alloc_specific (vtable);
4503 mono_object_new_alloc_specific (MonoVTable *vtable)
4507 if (!vtable->klass->has_references) {
4508 o = mono_object_new_ptrfree (vtable);
4509 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4510 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4512 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4513 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4515 if (G_UNLIKELY (vtable->klass->has_finalize))
4516 mono_object_register_finalizer (o);
4518 if (G_UNLIKELY (profile_allocs))
4519 mono_profiler_allocation (o, vtable->klass);
4524 mono_object_new_fast (MonoVTable *vtable)
4527 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4532 mono_object_new_ptrfree (MonoVTable *vtable)
4535 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4536 #if NEED_TO_ZERO_PTRFREE
4537 /* an inline memset is much faster for the common vcase of small objects
4538 * note we assume the allocated size is a multiple of sizeof (void*).
4540 if (vtable->klass->instance_size < 128) {
4542 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4543 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4549 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4556 mono_object_new_ptrfree_box (MonoVTable *vtable)
4559 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4560 /* the object will be boxed right away, no need to memzero it */
4565 * mono_class_get_allocation_ftn:
4567 * @for_box: the object will be used for boxing
4568 * @pass_size_in_words:
4570 * Return the allocation function appropriate for the given class.
4574 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4576 *pass_size_in_words = FALSE;
4578 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4579 profile_allocs = FALSE;
4581 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4582 return mono_object_new_specific;
4584 if (!vtable->klass->has_references) {
4585 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4587 return mono_object_new_ptrfree_box;
4588 return mono_object_new_ptrfree;
4591 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4593 return mono_object_new_fast;
4596 * FIXME: This is actually slower than mono_object_new_fast, because
4597 * of the overhead of parameter passing.
4600 *pass_size_in_words = TRUE;
4601 #ifdef GC_REDIRECT_TO_LOCAL
4602 return GC_local_gcj_fast_malloc;
4604 return GC_gcj_fast_malloc;
4609 return mono_object_new_specific;
4613 * mono_object_new_from_token:
4614 * @image: Context where the type_token is hosted
4615 * @token: a token of the type that we want to create
4617 * Returns: A newly created object whose definition is
4618 * looked up using @token in the @image image
4621 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4626 class = mono_class_get_checked (image, token, &error);
4627 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4629 return mono_object_new (domain, class);
4634 * mono_object_clone:
4635 * @obj: the object to clone
4637 * Returns: A newly created object who is a shallow copy of @obj
4640 mono_object_clone (MonoObject *obj)
4643 int size = obj->vtable->klass->instance_size;
4645 if (obj->vtable->klass->rank)
4646 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4648 o = mono_object_allocate (size, obj->vtable);
4650 if (obj->vtable->klass->has_references) {
4651 mono_gc_wbarrier_object_copy (o, obj);
4653 int size = obj->vtable->klass->instance_size;
4654 /* do not copy the sync state */
4655 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4657 if (G_UNLIKELY (profile_allocs))
4658 mono_profiler_allocation (o, obj->vtable->klass);
4660 if (obj->vtable->klass->has_finalize)
4661 mono_object_register_finalizer (o);
4666 * mono_array_full_copy:
4667 * @src: source array to copy
4668 * @dest: destination array
4670 * Copies the content of one array to another with exactly the same type and size.
4673 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4676 MonoClass *klass = src->obj.vtable->klass;
4678 g_assert (klass == dest->obj.vtable->klass);
4680 size = mono_array_length (src);
4681 g_assert (size == mono_array_length (dest));
4682 size *= mono_array_element_size (klass);
4684 if (klass->element_class->valuetype) {
4685 if (klass->element_class->has_references)
4686 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4688 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4690 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4693 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4698 * mono_array_clone_in_domain:
4699 * @domain: the domain in which the array will be cloned into
4700 * @array: the array to clone
4702 * This routine returns a copy of the array that is hosted on the
4703 * specified MonoDomain.
4706 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4711 MonoClass *klass = array->obj.vtable->klass;
4713 if (array->bounds == NULL) {
4714 size = mono_array_length (array);
4715 o = mono_array_new_full (domain, klass, &size, NULL);
4717 size *= mono_array_element_size (klass);
4719 if (klass->element_class->valuetype) {
4720 if (klass->element_class->has_references)
4721 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4723 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4725 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4728 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4733 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4734 size = mono_array_element_size (klass);
4735 for (i = 0; i < klass->rank; ++i) {
4736 sizes [i] = array->bounds [i].length;
4737 size *= array->bounds [i].length;
4738 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4740 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4742 if (klass->element_class->valuetype) {
4743 if (klass->element_class->has_references)
4744 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4746 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4748 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4751 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4759 * @array: the array to clone
4761 * Returns: A newly created array who is a shallow copy of @array
4764 mono_array_clone (MonoArray *array)
4766 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4769 /* helper macros to check for overflow when calculating the size of arrays */
4770 #ifdef MONO_BIG_ARRAYS
4771 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4772 #define MYGUINT_MAX MYGUINT64_MAX
4773 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4774 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4775 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4776 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4777 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4779 #define MYGUINT32_MAX 4294967295U
4780 #define MYGUINT_MAX MYGUINT32_MAX
4781 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4782 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4783 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4784 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4785 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4789 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4793 byte_len = mono_array_element_size (class);
4794 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4797 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4799 byte_len += sizeof (MonoArray);
4807 * mono_array_new_full:
4808 * @domain: domain where the object is created
4809 * @array_class: array class
4810 * @lengths: lengths for each dimension in the array
4811 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4813 * This routine creates a new array objects with the given dimensions,
4814 * lower bounds and type.
4817 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4819 uintptr_t byte_len = 0, len, bounds_size;
4822 MonoArrayBounds *bounds;
4826 if (!array_class->inited)
4827 mono_class_init (array_class);
4831 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4832 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4834 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4838 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4840 for (i = 0; i < array_class->rank; ++i) {
4841 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4843 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4844 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4849 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4850 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4854 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4855 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4856 byte_len = (byte_len + 3) & ~3;
4857 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4858 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4859 byte_len += bounds_size;
4862 * Following three lines almost taken from mono_object_new ():
4863 * they need to be kept in sync.
4865 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4866 #ifndef HAVE_SGEN_GC
4867 if (!array_class->has_references) {
4868 o = mono_object_allocate_ptrfree (byte_len, vtable);
4869 #if NEED_TO_ZERO_PTRFREE
4870 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4872 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4873 o = mono_object_allocate_spec (byte_len, vtable);
4875 o = mono_object_allocate (byte_len, vtable);
4878 array = (MonoArray*)o;
4879 array->max_length = len;
4882 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4883 array->bounds = bounds;
4887 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4889 o = mono_gc_alloc_vector (vtable, byte_len, len);
4890 array = (MonoArray*)o;
4892 bounds = array->bounds;
4896 for (i = 0; i < array_class->rank; ++i) {
4897 bounds [i].length = lengths [i];
4899 bounds [i].lower_bound = lower_bounds [i];
4903 if (G_UNLIKELY (profile_allocs))
4904 mono_profiler_allocation (o, array_class);
4911 * @domain: domain where the object is created
4912 * @eclass: element class
4913 * @n: number of array elements
4915 * This routine creates a new szarray with @n elements of type @eclass.
4918 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4922 ac = mono_array_class_get (eclass, 1);
4925 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4929 * mono_array_new_specific:
4930 * @vtable: a vtable in the appropriate domain for an initialized class
4931 * @n: number of array elements
4933 * This routine is a fast alternative to mono_array_new() for code which
4934 * can be sure about the domain it operates in.
4937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4943 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4948 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4949 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4952 #ifndef HAVE_SGEN_GC
4953 if (!vtable->klass->has_references) {
4954 o = mono_object_allocate_ptrfree (byte_len, vtable);
4955 #if NEED_TO_ZERO_PTRFREE
4956 ((MonoArray*)o)->bounds = NULL;
4957 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4959 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4960 o = mono_object_allocate_spec (byte_len, vtable);
4962 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4963 o = mono_object_allocate (byte_len, vtable);
4966 ao = (MonoArray *)o;
4969 o = mono_gc_alloc_vector (vtable, byte_len, n);
4973 if (G_UNLIKELY (profile_allocs))
4974 mono_profiler_allocation (o, vtable->klass);
4980 * mono_string_new_utf16:
4981 * @text: a pointer to an utf16 string
4982 * @len: the length of the string
4984 * Returns: A newly created string object which contains @text.
4987 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4991 s = mono_string_new_size (domain, len);
4992 g_assert (s != NULL);
4994 memcpy (mono_string_chars (s), text, len * 2);
5000 * mono_string_new_utf32:
5001 * @text: a pointer to an utf32 string
5002 * @len: the length of the string
5004 * Returns: A newly created string object which contains @text.
5007 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5010 mono_unichar2 *utf16_output = NULL;
5011 gint32 utf16_len = 0;
5012 GError *error = NULL;
5013 glong items_written;
5015 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5018 g_error_free (error);
5020 while (utf16_output [utf16_len]) utf16_len++;
5022 s = mono_string_new_size (domain, utf16_len);
5023 g_assert (s != NULL);
5025 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5027 g_free (utf16_output);
5033 * mono_string_new_size:
5034 * @text: a pointer to an utf16 string
5035 * @len: the length of the string
5037 * Returns: A newly created string object of @len
5040 mono_string_new_size (MonoDomain *domain, gint32 len)
5046 /* check for overflow */
5047 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 2) / 2))
5048 mono_gc_out_of_memory (-1);
5050 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5051 g_assert (size > 0);
5053 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5056 #ifndef HAVE_SGEN_GC
5057 s = mono_object_allocate_ptrfree (size, vtable);
5061 s = mono_gc_alloc_string (vtable, size, len);
5063 #if NEED_TO_ZERO_PTRFREE
5066 if (G_UNLIKELY (profile_allocs))
5067 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5073 * mono_string_new_len:
5074 * @text: a pointer to an utf8 string
5075 * @length: number of bytes in @text to consider
5077 * Returns: A newly created string object which contains @text.
5080 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5082 GError *error = NULL;
5083 MonoString *o = NULL;
5085 glong items_written;
5087 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5090 o = mono_string_new_utf16 (domain, ut, items_written);
5092 g_error_free (error);
5101 * @text: a pointer to an utf8 string
5103 * Returns: A newly created string object which contains @text.
5106 mono_string_new (MonoDomain *domain, const char *text)
5108 GError *error = NULL;
5109 MonoString *o = NULL;
5111 glong items_written;
5116 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5119 o = mono_string_new_utf16 (domain, ut, items_written);
5121 g_error_free (error);
5124 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5129 MonoString *o = NULL;
5131 if (!g_utf8_validate (text, -1, &end))
5134 len = g_utf8_strlen (text, -1);
5135 o = mono_string_new_size (domain, len);
5136 str = mono_string_chars (o);
5138 while (text < end) {
5139 *str++ = g_utf8_get_char (text);
5140 text = g_utf8_next_char (text);
5147 * mono_string_new_wrapper:
5148 * @text: pointer to utf8 characters.
5150 * Helper function to create a string object from @text in the current domain.
5153 mono_string_new_wrapper (const char *text)
5155 MonoDomain *domain = mono_domain_get ();
5158 return mono_string_new (domain, text);
5165 * @class: the class of the value
5166 * @value: a pointer to the unboxed data
5168 * Returns: A newly created object which contains @value.
5171 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5177 g_assert (class->valuetype);
5178 if (mono_class_is_nullable (class))
5179 return mono_nullable_box (value, class);
5181 vtable = mono_class_vtable (domain, class);
5184 size = mono_class_instance_size (class);
5185 res = mono_object_new_alloc_specific (vtable);
5186 if (G_UNLIKELY (profile_allocs))
5187 mono_profiler_allocation (res, class);
5189 size = size - sizeof (MonoObject);
5192 g_assert (size == mono_class_value_size (class, NULL));
5193 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5195 #if NO_UNALIGNED_ACCESS
5196 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5200 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5203 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5206 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5209 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5212 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5216 if (class->has_finalize)
5217 mono_object_register_finalizer (res);
5223 * @dest: destination pointer
5224 * @src: source pointer
5225 * @klass: a valuetype class
5227 * Copy a valuetype from @src to @dest. This function must be used
5228 * when @klass contains references fields.
5231 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5233 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5237 * mono_value_copy_array:
5238 * @dest: destination array
5239 * @dest_idx: index in the @dest array
5240 * @src: source pointer
5241 * @count: number of items
5243 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5244 * This function must be used when @klass contains references fields.
5245 * Overlap is handled.
5248 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5250 int size = mono_array_element_size (dest->obj.vtable->klass);
5251 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5252 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5253 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5257 * mono_object_get_domain:
5258 * @obj: object to query
5260 * Returns: the MonoDomain where the object is hosted
5263 mono_object_get_domain (MonoObject *obj)
5265 return mono_object_domain (obj);
5269 * mono_object_get_class:
5270 * @obj: object to query
5272 * Returns: the MonOClass of the object.
5275 mono_object_get_class (MonoObject *obj)
5277 return mono_object_class (obj);
5280 * mono_object_get_size:
5281 * @o: object to query
5283 * Returns: the size, in bytes, of @o
5286 mono_object_get_size (MonoObject* o)
5288 MonoClass* klass = mono_object_class (o);
5289 if (klass == mono_defaults.string_class) {
5290 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5291 } else if (o->vtable->rank) {
5292 MonoArray *array = (MonoArray*)o;
5293 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5294 if (array->bounds) {
5297 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5301 return mono_class_instance_size (klass);
5306 * mono_object_unbox:
5307 * @obj: object to unbox
5309 * Returns: a pointer to the start of the valuetype boxed in this
5312 * This method will assert if the object passed is not a valuetype.
5315 mono_object_unbox (MonoObject *obj)
5317 /* add assert for valuetypes? */
5318 g_assert (obj->vtable->klass->valuetype);
5319 return ((char*)obj) + sizeof (MonoObject);
5323 * mono_object_isinst:
5325 * @klass: a pointer to a class
5327 * Returns: @obj if @obj is derived from @klass
5330 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5333 mono_class_init (klass);
5335 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5336 return mono_object_isinst_mbyref (obj, klass);
5341 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5345 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5354 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5355 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5359 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5360 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5363 MonoClass *oklass = vt->klass;
5364 if (mono_class_is_transparent_proxy (oklass))
5365 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5367 mono_class_setup_supertypes (klass);
5368 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5371 #ifndef DISABLE_REMOTING
5372 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5374 MonoDomain *domain = mono_domain_get ();
5376 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5377 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5378 MonoMethod *im = NULL;
5381 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5382 im = mono_object_get_virtual_method (rp, im);
5385 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5388 res = mono_runtime_invoke (im, rp, pa, NULL);
5390 if (*(MonoBoolean *) mono_object_unbox(res)) {
5391 /* Update the vtable of the remote type, so it can safely cast to this new type */
5392 mono_upgrade_remote_class (domain, obj, klass);
5396 #endif /* DISABLE_REMOTING */
5401 * mono_object_castclass_mbyref:
5403 * @klass: a pointer to a class
5405 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5408 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5410 if (!obj) return NULL;
5411 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5413 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5415 "InvalidCastException"));
5420 MonoDomain *orig_domain;
5426 str_lookup (MonoDomain *domain, gpointer user_data)
5428 LDStrInfo *info = user_data;
5429 if (info->res || domain == info->orig_domain)
5431 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5437 mono_string_get_pinned (MonoString *str)
5441 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5442 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5444 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5445 news->length = mono_string_length (str);
5451 #define mono_string_get_pinned(str) (str)
5455 mono_string_is_interned_lookup (MonoString *str, int insert)
5457 MonoGHashTable *ldstr_table;
5461 domain = ((MonoObject *)str)->vtable->domain;
5462 ldstr_table = domain->ldstr_table;
5464 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5469 str = mono_string_get_pinned (str);
5471 mono_g_hash_table_insert (ldstr_table, str, str);
5475 LDStrInfo ldstr_info;
5476 ldstr_info.orig_domain = domain;
5477 ldstr_info.ins = str;
5478 ldstr_info.res = NULL;
5480 mono_domain_foreach (str_lookup, &ldstr_info);
5481 if (ldstr_info.res) {
5483 * the string was already interned in some other domain:
5484 * intern it in the current one as well.
5486 mono_g_hash_table_insert (ldstr_table, str, str);
5496 * mono_string_is_interned:
5497 * @o: String to probe
5499 * Returns whether the string has been interned.
5502 mono_string_is_interned (MonoString *o)
5504 return mono_string_is_interned_lookup (o, FALSE);
5508 * mono_string_intern:
5509 * @o: String to intern
5511 * Interns the string passed.
5512 * Returns: The interned string.
5515 mono_string_intern (MonoString *str)
5517 return mono_string_is_interned_lookup (str, TRUE);
5522 * @domain: the domain where the string will be used.
5523 * @image: a metadata context
5524 * @idx: index into the user string table.
5526 * Implementation for the ldstr opcode.
5527 * Returns: a loaded string from the @image/@idx combination.
5530 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5532 if (image->dynamic) {
5533 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5536 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5537 return NULL; /*FIXME we should probably be raising an exception here*/
5538 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5543 * mono_ldstr_metadata_sig
5544 * @domain: the domain for the string
5545 * @sig: the signature of a metadata string
5547 * Returns: a MonoString for a string stored in the metadata
5550 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5552 const char *str = sig;
5553 MonoString *o, *interned;
5556 len2 = mono_metadata_decode_blob_size (str, &str);
5559 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5560 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5563 guint16 *p2 = (guint16*)mono_string_chars (o);
5564 for (i = 0; i < len2; ++i) {
5565 *p2 = GUINT16_FROM_LE (*p2);
5571 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5573 /* o will get garbage collected */
5577 o = mono_string_get_pinned (o);
5579 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5586 * mono_string_to_utf8:
5587 * @s: a System.String
5589 * Returns the UTF8 representation for @s.
5590 * The resulting buffer needs to be freed with mono_free().
5592 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5595 mono_string_to_utf8 (MonoString *s)
5598 char *result = mono_string_to_utf8_checked (s, &error);
5600 if (!mono_error_ok (&error))
5601 mono_error_raise_exception (&error);
5606 * mono_string_to_utf8_checked:
5607 * @s: a System.String
5608 * @error: a MonoError.
5610 * Converts a MonoString to its UTF8 representation. May fail; check
5611 * @error to determine whether the conversion was successful.
5612 * The resulting buffer should be freed with mono_free().
5615 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5619 GError *gerror = NULL;
5621 mono_error_init (error);
5627 return g_strdup ("");
5629 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5631 mono_error_set_argument (error, "string", "%s", gerror->message);
5632 g_error_free (gerror);
5635 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5636 if (s->length > written) {
5637 /* allocate the total length and copy the part of the string that has been converted */
5638 char *as2 = g_malloc0 (s->length);
5639 memcpy (as2, as, written);
5648 * mono_string_to_utf8_ignore:
5651 * Converts a MonoString to its UTF8 representation. Will ignore
5652 * invalid surrogate pairs.
5653 * The resulting buffer should be freed with mono_free().
5657 mono_string_to_utf8_ignore (MonoString *s)
5666 return g_strdup ("");
5668 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5670 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5671 if (s->length > written) {
5672 /* allocate the total length and copy the part of the string that has been converted */
5673 char *as2 = g_malloc0 (s->length);
5674 memcpy (as2, as, written);
5683 * mono_string_to_utf8_image_ignore:
5684 * @s: a System.String
5686 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5689 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5691 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5695 * mono_string_to_utf8_mp_ignore:
5696 * @s: a System.String
5698 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5701 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5703 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5708 * mono_string_to_utf16:
5711 * Return an null-terminated array of the utf-16 chars
5712 * contained in @s. The result must be freed with g_free().
5713 * This is a temporary helper until our string implementation
5714 * is reworked to always include the null terminating char.
5717 mono_string_to_utf16 (MonoString *s)
5724 as = g_malloc ((s->length * 2) + 2);
5725 as [(s->length * 2)] = '\0';
5726 as [(s->length * 2) + 1] = '\0';
5729 return (gunichar2 *)(as);
5732 memcpy (as, mono_string_chars(s), s->length * 2);
5733 return (gunichar2 *)(as);
5737 * mono_string_to_utf32:
5740 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5741 * contained in @s. The result must be freed with g_free().
5744 mono_string_to_utf32 (MonoString *s)
5746 mono_unichar4 *utf32_output = NULL;
5747 GError *error = NULL;
5748 glong items_written;
5753 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5756 g_error_free (error);
5758 return utf32_output;
5762 * mono_string_from_utf16:
5763 * @data: the UTF16 string (LPWSTR) to convert
5765 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5767 * Returns: a MonoString.
5770 mono_string_from_utf16 (gunichar2 *data)
5772 MonoDomain *domain = mono_domain_get ();
5778 while (data [len]) len++;
5780 return mono_string_new_utf16 (domain, data, len);
5784 * mono_string_from_utf32:
5785 * @data: the UTF32 string (LPWSTR) to convert
5787 * Converts a UTF32 (UCS-4)to a MonoString.
5789 * Returns: a MonoString.
5792 mono_string_from_utf32 (mono_unichar4 *data)
5794 MonoString* result = NULL;
5795 mono_unichar2 *utf16_output = NULL;
5796 GError *error = NULL;
5797 glong items_written;
5803 while (data [len]) len++;
5805 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5808 g_error_free (error);
5810 result = mono_string_from_utf16 (utf16_output);
5811 g_free (utf16_output);
5816 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5823 r = mono_string_to_utf8_ignore (s);
5825 r = mono_string_to_utf8_checked (s, error);
5826 if (!mono_error_ok (error))
5833 len = strlen (r) + 1;
5835 mp_s = mono_mempool_alloc (mp, len);
5837 mp_s = mono_image_alloc (image, len);
5839 memcpy (mp_s, r, len);
5847 * mono_string_to_utf8_image:
5848 * @s: a System.String
5850 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5853 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5855 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5859 * mono_string_to_utf8_mp:
5860 * @s: a System.String
5862 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5865 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5867 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5871 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5874 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5876 eh_callbacks = *cbs;
5879 MonoRuntimeExceptionHandlingCallbacks *
5880 mono_get_eh_callbacks (void)
5882 return &eh_callbacks;
5886 * mono_raise_exception:
5887 * @ex: exception object
5889 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5892 mono_raise_exception (MonoException *ex)
5895 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5896 * that will cause gcc to omit the function epilog, causing problems when
5897 * the JIT tries to walk the stack, since the return address on the stack
5898 * will point into the next function in the executable, not this one.
5900 eh_callbacks.mono_raise_exception (ex);
5904 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5906 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5910 * mono_wait_handle_new:
5911 * @domain: Domain where the object will be created
5912 * @handle: Handle for the wait handle
5914 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5917 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5919 MonoWaitHandle *res;
5920 gpointer params [1];
5921 static MonoMethod *handle_set;
5923 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5925 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5927 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5929 params [0] = &handle;
5930 mono_runtime_invoke (handle_set, res, params, NULL);
5936 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5938 static MonoClassField *f_os_handle;
5939 static MonoClassField *f_safe_handle;
5941 if (!f_os_handle && !f_safe_handle) {
5942 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5943 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5948 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5952 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5959 mono_runtime_capture_context (MonoDomain *domain)
5961 RuntimeInvokeFunction runtime_invoke;
5963 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5964 MonoMethod *method = mono_get_context_capture_method ();
5965 MonoMethod *wrapper;
5968 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5969 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5970 domain->capture_context_method = mono_compile_method (method);
5973 runtime_invoke = domain->capture_context_runtime_invoke;
5975 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5978 * mono_async_result_new:
5979 * @domain:domain where the object will be created.
5980 * @handle: wait handle.
5981 * @state: state to pass to AsyncResult
5982 * @data: C closure data.
5984 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5985 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5989 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5991 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5992 MonoObject *context = mono_runtime_capture_context (domain);
5993 /* we must capture the execution context from the original thread */
5995 MONO_OBJECT_SETREF (res, execution_context, context);
5996 /* note: result may be null if the flow is suppressed */
6000 MONO_OBJECT_SETREF (res, object_data, object_data);
6001 MONO_OBJECT_SETREF (res, async_state, state);
6003 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6005 res->sync_completed = FALSE;
6006 res->completed = FALSE;
6012 mono_message_init (MonoDomain *domain,
6013 MonoMethodMessage *this,
6014 MonoReflectionMethod *method,
6015 MonoArray *out_args)
6017 static MonoClass *object_array_klass;
6018 static MonoClass *byte_array_klass;
6019 static MonoClass *string_array_klass;
6020 MonoMethodSignature *sig = mono_method_signature (method->method);
6026 if (!object_array_klass) {
6029 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6031 byte_array_klass = klass;
6033 klass = mono_array_class_get (mono_defaults.string_class, 1);
6035 string_array_klass = klass;
6037 klass = mono_array_class_get (mono_defaults.object_class, 1);
6040 mono_atomic_store_release (&object_array_klass, klass);
6043 MONO_OBJECT_SETREF (this, method, method);
6045 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6046 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6047 this->async_result = NULL;
6048 this->call_type = CallType_Sync;
6050 names = g_new (char *, sig->param_count);
6051 mono_method_get_param_names (method->method, (const char **) names);
6052 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6054 for (i = 0; i < sig->param_count; i++) {
6055 name = mono_string_new (domain, names [i]);
6056 mono_array_setref (this->names, i, name);
6060 for (i = 0, j = 0; i < sig->param_count; i++) {
6061 if (sig->params [i]->byref) {
6063 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6064 mono_array_setref (this->args, i, arg);
6068 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6072 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6075 mono_array_set (this->arg_types, guint8, i, arg_type);
6079 #ifndef DISABLE_REMOTING
6081 * mono_remoting_invoke:
6082 * @real_proxy: pointer to a RealProxy object
6083 * @msg: The MonoMethodMessage to execute
6084 * @exc: used to store exceptions
6085 * @out_args: used to store output arguments
6087 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6088 * IMessage interface and it is not trivial to extract results from there. So
6089 * we call an helper method PrivateInvoke instead of calling
6090 * RealProxy::Invoke() directly.
6092 * Returns: the result object.
6095 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6096 MonoObject **exc, MonoArray **out_args)
6098 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6101 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6104 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6106 real_proxy->vtable->domain->private_invoke_method = im;
6109 pa [0] = real_proxy;
6114 return mono_runtime_invoke (im, NULL, pa, exc);
6119 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6120 MonoObject **exc, MonoArray **out_args)
6122 static MonoClass *object_array_klass;
6125 MonoMethodSignature *sig;
6127 int i, j, outarg_count = 0;
6129 #ifndef DISABLE_REMOTING
6130 if (target && mono_object_is_transparent_proxy (target)) {
6131 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6132 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6133 target = tp->rp->unwrapped_server;
6135 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6140 domain = mono_domain_get ();
6141 method = msg->method->method;
6142 sig = mono_method_signature (method);
6144 for (i = 0; i < sig->param_count; i++) {
6145 if (sig->params [i]->byref)
6149 if (!object_array_klass) {
6152 klass = mono_array_class_get (mono_defaults.object_class, 1);
6155 mono_memory_barrier ();
6156 object_array_klass = klass;
6159 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6160 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6163 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6165 for (i = 0, j = 0; i < sig->param_count; i++) {
6166 if (sig->params [i]->byref) {
6168 arg = mono_array_get (msg->args, gpointer, i);
6169 mono_array_setref (*out_args, j, arg);
6178 * mono_object_to_string:
6180 * @exc: Any exception thrown by ToString (). May be NULL.
6182 * Returns: the result of calling ToString () on an object.
6185 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6187 static MonoMethod *to_string = NULL;
6194 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6196 method = mono_object_get_virtual_method (obj, to_string);
6198 // Unbox value type if needed
6199 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6200 target = mono_object_unbox (obj);
6203 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6207 * mono_print_unhandled_exception:
6208 * @exc: The exception
6210 * Prints the unhandled exception.
6213 mono_print_unhandled_exception (MonoObject *exc)
6216 char *message = (char*)"";
6217 gboolean free_message = FALSE;
6220 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6221 message = g_strdup ("OutOfMemoryException");
6222 free_message = TRUE;
6225 if (((MonoException*)exc)->native_trace_ips) {
6226 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6227 free_message = TRUE;
6229 MonoObject *other_exc = NULL;
6230 str = mono_object_to_string (exc, &other_exc);
6232 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6233 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6235 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6236 original_backtrace, nested_backtrace);
6238 g_free (original_backtrace);
6239 g_free (nested_backtrace);
6240 free_message = TRUE;
6242 message = mono_string_to_utf8_checked (str, &error);
6243 if (!mono_error_ok (&error)) {
6244 mono_error_cleanup (&error);
6245 message = (char *) "";
6247 free_message = TRUE;
6254 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6255 * exc->vtable->klass->name, message);
6257 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6264 * mono_delegate_ctor:
6265 * @this: pointer to an uninitialized delegate object
6266 * @target: target object
6267 * @addr: pointer to native code
6270 * Initialize a delegate and sets a specific method, not the one
6271 * associated with addr. This is useful when sharing generic code.
6272 * In that case addr will most probably not be associated with the
6273 * correct instantiation of the method.
6276 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6278 MonoDelegate *delegate = (MonoDelegate *)this;
6285 delegate->method = method;
6287 class = this->vtable->klass;
6288 mono_stats.delegate_creations++;
6290 #ifndef DISABLE_REMOTING
6291 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6293 method = mono_marshal_get_remoting_invoke (method);
6294 delegate->method_ptr = mono_compile_method (method);
6295 MONO_OBJECT_SETREF (delegate, target, target);
6299 delegate->method_ptr = addr;
6300 MONO_OBJECT_SETREF (delegate, target, target);
6303 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6307 * mono_delegate_ctor:
6308 * @this: pointer to an uninitialized delegate object
6309 * @target: target object
6310 * @addr: pointer to native code
6312 * This is used to initialize a delegate.
6315 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6317 MonoDomain *domain = mono_domain_get ();
6319 MonoMethod *method = NULL;
6323 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6325 if (!ji && domain != mono_get_root_domain ())
6326 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6328 method = mono_jit_info_get_method (ji);
6329 g_assert (!method->klass->generic_container);
6332 mono_delegate_ctor_with_method (this, target, addr, method);
6336 * mono_method_call_message_new:
6337 * @method: method to encapsulate
6338 * @params: parameters to the method
6339 * @invoke: optional, delegate invoke.
6340 * @cb: async callback delegate.
6341 * @state: state passed to the async callback.
6343 * Translates arguments pointers into a MonoMethodMessage.
6346 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6347 MonoDelegate **cb, MonoObject **state)
6349 MonoDomain *domain = mono_domain_get ();
6350 MonoMethodSignature *sig = mono_method_signature (method);
6351 MonoMethodMessage *msg;
6354 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6357 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6358 count = sig->param_count - 2;
6360 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6361 count = sig->param_count;
6364 for (i = 0; i < count; i++) {
6369 if (sig->params [i]->byref)
6370 vpos = *((gpointer *)params [i]);
6374 type = sig->params [i]->type;
6375 class = mono_class_from_mono_type (sig->params [i]);
6377 if (class->valuetype)
6378 arg = mono_value_box (domain, class, vpos);
6380 arg = *((MonoObject **)vpos);
6382 mono_array_setref (msg->args, i, arg);
6385 if (cb != NULL && state != NULL) {
6386 *cb = *((MonoDelegate **)params [i]);
6388 *state = *((MonoObject **)params [i]);
6395 * mono_method_return_message_restore:
6397 * Restore results from message based processing back to arguments pointers
6400 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6402 MonoMethodSignature *sig = mono_method_signature (method);
6403 int i, j, type, size, out_len;
6405 if (out_args == NULL)
6407 out_len = mono_array_length (out_args);
6411 for (i = 0, j = 0; i < sig->param_count; i++) {
6412 MonoType *pt = sig->params [i];
6417 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6419 arg = mono_array_get (out_args, gpointer, j);
6422 g_assert (type != MONO_TYPE_VOID);
6424 if (MONO_TYPE_IS_REFERENCE (pt)) {
6425 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6428 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6429 size = mono_class_value_size (class, NULL);
6430 if (class->has_references)
6431 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6433 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6435 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6436 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6445 #ifndef DISABLE_REMOTING
6448 * mono_load_remote_field:
6449 * @this: pointer to an object
6450 * @klass: klass of the object containing @field
6451 * @field: the field to load
6452 * @res: a storage to store the result
6454 * This method is called by the runtime on attempts to load fields of
6455 * transparent proxy objects. @this points to such TP, @klass is the class of
6456 * the object containing @field. @res is a storage location which can be
6457 * used to store the result.
6459 * Returns: an address pointing to the value of field.
6462 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6464 static MonoMethod *getter = NULL;
6465 MonoDomain *domain = mono_domain_get ();
6466 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6467 MonoClass *field_class;
6468 MonoMethodMessage *msg;
6469 MonoArray *out_args;
6473 g_assert (mono_object_is_transparent_proxy (this));
6474 g_assert (res != NULL);
6476 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6477 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6482 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6486 field_class = mono_class_from_mono_type (field->type);
6488 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6489 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6490 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6492 full_name = mono_type_get_full_name (klass);
6493 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6494 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6497 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6499 if (exc) mono_raise_exception ((MonoException *)exc);
6501 if (mono_array_length (out_args) == 0)
6504 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6506 if (field_class->valuetype) {
6507 return ((char *)*res) + sizeof (MonoObject);
6513 * mono_load_remote_field_new:
6518 * Missing documentation.
6521 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6523 static MonoMethod *getter = NULL;
6524 MonoDomain *domain = mono_domain_get ();
6525 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6526 MonoClass *field_class;
6527 MonoMethodMessage *msg;
6528 MonoArray *out_args;
6529 MonoObject *exc, *res;
6532 g_assert (mono_object_is_transparent_proxy (this));
6534 field_class = mono_class_from_mono_type (field->type);
6536 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6538 if (field_class->valuetype) {
6539 res = mono_object_new (domain, field_class);
6540 val = ((gchar *) res) + sizeof (MonoObject);
6544 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6549 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6553 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6554 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6556 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6558 full_name = mono_type_get_full_name (klass);
6559 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6560 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6563 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6565 if (exc) mono_raise_exception ((MonoException *)exc);
6567 if (mono_array_length (out_args) == 0)
6570 res = mono_array_get (out_args, MonoObject *, 0);
6576 * mono_store_remote_field:
6577 * @this: pointer to an object
6578 * @klass: klass of the object containing @field
6579 * @field: the field to load
6580 * @val: the value/object to store
6582 * This method is called by the runtime on attempts to store fields of
6583 * transparent proxy objects. @this points to such TP, @klass is the class of
6584 * the object containing @field. @val is the new value to store in @field.
6587 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6589 static MonoMethod *setter = NULL;
6590 MonoDomain *domain = mono_domain_get ();
6591 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6592 MonoClass *field_class;
6593 MonoMethodMessage *msg;
6594 MonoArray *out_args;
6599 g_assert (mono_object_is_transparent_proxy (this));
6601 field_class = mono_class_from_mono_type (field->type);
6603 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6604 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6605 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6610 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6614 if (field_class->valuetype)
6615 arg = mono_value_box (domain, field_class, val);
6617 arg = *((MonoObject **)val);
6620 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6621 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6623 full_name = mono_type_get_full_name (klass);
6624 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6625 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6626 mono_array_setref (msg->args, 2, arg);
6629 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6631 if (exc) mono_raise_exception ((MonoException *)exc);
6635 * mono_store_remote_field_new:
6641 * Missing documentation
6644 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6646 static MonoMethod *setter = NULL;
6647 MonoDomain *domain = mono_domain_get ();
6648 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6649 MonoClass *field_class;
6650 MonoMethodMessage *msg;
6651 MonoArray *out_args;
6655 g_assert (mono_object_is_transparent_proxy (this));
6657 field_class = mono_class_from_mono_type (field->type);
6659 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6660 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6661 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6666 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6670 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6671 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6673 full_name = mono_type_get_full_name (klass);
6674 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6675 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6676 mono_array_setref (msg->args, 2, arg);
6679 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6681 if (exc) mono_raise_exception ((MonoException *)exc);
6686 * mono_create_ftnptr:
6688 * Given a function address, create a function descriptor for it.
6689 * This is only needed on some platforms.
6692 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6694 return callbacks.create_ftnptr (domain, addr);
6698 * mono_get_addr_from_ftnptr:
6700 * Given a pointer to a function descriptor, return the function address.
6701 * This is only needed on some platforms.
6704 mono_get_addr_from_ftnptr (gpointer descr)
6706 return callbacks.get_addr_from_ftnptr (descr);
6710 * mono_string_chars:
6713 * Returns a pointer to the UCS16 characters stored in the MonoString
6716 mono_string_chars (MonoString *s)
6722 * mono_string_length:
6725 * Returns the lenght in characters of the string
6728 mono_string_length (MonoString *s)
6734 * mono_array_length:
6735 * @array: a MonoArray*
6737 * Returns the total number of elements in the array. This works for
6738 * both vectors and multidimensional arrays.
6741 mono_array_length (MonoArray *array)
6743 return array->max_length;
6747 * mono_array_addr_with_size:
6748 * @array: a MonoArray*
6749 * @size: size of the array elements
6750 * @idx: index into the array
6752 * Returns the address of the @idx element in the array.
6755 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6757 return ((char*)(array)->vector) + size * idx;