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;
149 mono_type_init_lock (TypeInitializationLock *lock)
151 MONO_PREPARE_BLOCKING
152 mono_mutex_lock (&lock->initialization_section);
157 mono_type_init_unlock (TypeInitializationLock *lock)
159 mono_mutex_unlock (&lock->initialization_section);
162 /* from vtable to lock */
163 static GHashTable *type_initialization_hash;
165 /* from thread id to thread id being waited on */
166 static GHashTable *blocked_thread_hash;
169 static MonoThread *main_thread;
171 /* Functions supplied by the runtime */
172 static MonoRuntimeCallbacks callbacks;
175 * mono_thread_set_main:
176 * @thread: thread to set as the main thread
178 * This function can be used to instruct the runtime to treat @thread
179 * as the main thread, ie, the thread that would normally execute the Main()
180 * method. This basically means that at the end of @thread, the runtime will
181 * wait for the existing foreground threads to quit and other such details.
184 mono_thread_set_main (MonoThread *thread)
186 static gboolean registered = FALSE;
189 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
193 main_thread = thread;
197 mono_thread_get_main (void)
203 mono_type_initialization_init (void)
205 mono_mutex_init_recursive (&type_initialization_section);
206 type_initialization_hash = g_hash_table_new (NULL, NULL);
207 blocked_thread_hash = g_hash_table_new (NULL, NULL);
208 mono_mutex_init_recursive (&ldstr_section);
212 mono_type_initialization_cleanup (void)
215 /* This is causing race conditions with
216 * mono_release_type_locks
218 mono_mutex_destroy (&type_initialization_section);
219 g_hash_table_destroy (type_initialization_hash);
220 type_initialization_hash = NULL;
222 mono_mutex_destroy (&ldstr_section);
223 g_hash_table_destroy (blocked_thread_hash);
224 blocked_thread_hash = NULL;
230 * get_type_init_exception_for_vtable:
232 * Return the stored type initialization exception for VTABLE.
234 static MonoException*
235 get_type_init_exception_for_vtable (MonoVTable *vtable)
237 MonoDomain *domain = vtable->domain;
238 MonoClass *klass = vtable->klass;
242 if (!vtable->init_failed)
243 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
246 * If the initializing thread was rudely aborted, the exception is not stored
250 mono_domain_lock (domain);
251 if (domain->type_init_exception_hash)
252 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
253 mono_domain_unlock (domain);
256 if (klass->name_space && *klass->name_space)
257 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
259 full_name = g_strdup (klass->name);
260 ex = mono_get_exception_type_initialization (full_name, NULL);
267 * mono_runtime_class_init:
268 * @vtable: vtable that needs to be initialized
270 * This routine calls the class constructor for @vtable.
273 mono_runtime_class_init (MonoVTable *vtable)
275 mono_runtime_class_init_full (vtable, TRUE);
279 * mono_runtime_class_init_full:
280 * @vtable that neeeds to be initialized
281 * @raise_exception is TRUE, exceptions are raised intead of returned
285 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
288 MonoException *exc_to_throw;
289 MonoMethod *method = NULL;
293 if (vtable->initialized)
297 klass = vtable->klass;
299 if (!klass->image->checked_module_cctor) {
300 mono_image_check_for_module_cctor (klass->image);
301 if (klass->image->has_module_cctor) {
303 MonoClass *module_klass;
304 MonoVTable *module_vtable;
306 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
308 exc = mono_error_convert_to_exception (&error);
310 mono_raise_exception (exc);
314 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
317 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
322 method = mono_class_get_cctor (klass);
325 MonoDomain *domain = vtable->domain;
326 TypeInitializationLock *lock;
327 guint32 tid = GetCurrentThreadId();
328 int do_initialization = 0;
329 MonoDomain *last_domain = NULL;
331 mono_type_initialization_lock ();
332 /* double check... */
333 if (vtable->initialized) {
334 mono_type_initialization_unlock ();
337 if (vtable->init_failed) {
338 mono_type_initialization_unlock ();
340 /* The type initialization already failed once, rethrow the same exception */
342 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
343 return get_type_init_exception_for_vtable (vtable);
345 lock = g_hash_table_lookup (type_initialization_hash, vtable);
347 /* This thread will get to do the initialization */
348 if (mono_domain_get () != domain) {
349 /* Transfer into the target domain */
350 last_domain = mono_domain_get ();
351 if (!mono_domain_set (domain, FALSE)) {
352 vtable->initialized = 1;
353 mono_type_initialization_unlock ();
355 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
356 return mono_get_exception_appdomain_unloaded ();
359 lock = g_malloc (sizeof(TypeInitializationLock));
360 mono_mutex_init_recursive (&lock->initialization_section);
361 lock->initializing_tid = tid;
362 lock->waiting_count = 1;
364 /* grab the vtable lock while this thread still owns type_initialization_section */
365 mono_type_init_lock (lock);
366 g_hash_table_insert (type_initialization_hash, vtable, lock);
367 do_initialization = 1;
370 TypeInitializationLock *pending_lock;
372 if (lock->initializing_tid == tid || lock->done) {
373 mono_type_initialization_unlock ();
376 /* see if the thread doing the initialization is already blocked on this thread */
377 blocked = GUINT_TO_POINTER (lock->initializing_tid);
378 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
379 if (pending_lock->initializing_tid == tid) {
380 if (!pending_lock->done) {
381 mono_type_initialization_unlock ();
384 /* the thread doing the initialization is blocked on this thread,
385 but on a lock that has already been freed. It just hasn't got
390 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
392 ++lock->waiting_count;
393 /* record the fact that we are waiting on the initializing thread */
394 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
396 mono_type_initialization_unlock ();
398 if (do_initialization) {
399 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
401 /* If the initialization failed, mark the class as unusable. */
402 /* Avoid infinite loops */
404 (klass->image == mono_defaults.corlib &&
405 !strcmp (klass->name_space, "System") &&
406 !strcmp (klass->name, "TypeInitializationException")))) {
407 vtable->init_failed = 1;
409 if (klass->name_space && *klass->name_space)
410 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
412 full_name = g_strdup (klass->name);
413 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
417 * Store the exception object so it could be thrown on subsequent
420 mono_domain_lock (domain);
421 if (!domain->type_init_exception_hash)
422 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
423 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
424 mono_domain_unlock (domain);
428 mono_domain_set (last_domain, TRUE);
430 mono_type_init_unlock (lock);
432 /* this just blocks until the initializing thread is done */
433 mono_type_init_lock (lock);
434 mono_type_init_unlock (lock);
437 mono_type_initialization_lock ();
438 if (lock->initializing_tid != tid)
439 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
440 --lock->waiting_count;
441 if (lock->waiting_count == 0) {
442 mono_mutex_destroy (&lock->initialization_section);
443 g_hash_table_remove (type_initialization_hash, vtable);
446 mono_memory_barrier ();
447 if (!vtable->init_failed)
448 vtable->initialized = 1;
449 mono_type_initialization_unlock ();
451 if (vtable->init_failed) {
452 /* Either we were the initializing thread or we waited for the initialization */
454 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
455 return get_type_init_exception_for_vtable (vtable);
458 vtable->initialized = 1;
465 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
467 MonoVTable *vtable = (MonoVTable*)key;
469 TypeInitializationLock *lock = (TypeInitializationLock*) value;
470 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
473 * Have to set this since it cannot be set by the normal code in
474 * mono_runtime_class_init (). In this case, the exception object is not stored,
475 * and get_type_init_exception_for_class () needs to be aware of this.
477 vtable->init_failed = 1;
478 mono_type_init_unlock (lock);
479 --lock->waiting_count;
480 if (lock->waiting_count == 0) {
481 mono_mutex_destroy (&lock->initialization_section);
490 mono_release_type_locks (MonoInternalThread *thread)
492 mono_type_initialization_lock ();
493 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
494 mono_type_initialization_unlock ();
498 default_trampoline (MonoMethod *method)
504 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
506 g_assert_not_reached ();
511 #ifndef DISABLE_REMOTING
514 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
516 g_error ("remoting not installed");
520 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
524 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
526 g_assert_not_reached ();
530 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
531 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
532 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
533 static MonoImtThunkBuilder imt_thunk_builder = NULL;
534 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
535 #if (MONO_IMT_SIZE > 32)
536 #error "MONO_IMT_SIZE cannot be larger than 32"
540 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
542 memcpy (&callbacks, cbs, sizeof (*cbs));
545 MonoRuntimeCallbacks*
546 mono_get_runtime_callbacks (void)
552 mono_install_trampoline (MonoTrampoline func)
554 arch_create_jit_trampoline = func? func: default_trampoline;
558 mono_install_jump_trampoline (MonoJumpTrampoline func)
560 arch_create_jump_trampoline = func? func: default_jump_trampoline;
563 #ifndef DISABLE_REMOTING
565 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
567 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
572 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
574 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
578 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
579 imt_thunk_builder = func;
582 static MonoCompileFunc default_mono_compile_method = NULL;
585 * mono_install_compile_method:
586 * @func: function to install
588 * This is a VM internal routine
591 mono_install_compile_method (MonoCompileFunc func)
593 default_mono_compile_method = func;
597 * mono_compile_method:
598 * @method: The method to compile.
600 * This JIT-compiles the method, and returns the pointer to the native code
604 mono_compile_method (MonoMethod *method)
606 if (!default_mono_compile_method) {
607 g_error ("compile method called on uninitialized runtime");
610 return default_mono_compile_method (method);
614 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
616 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
620 mono_runtime_create_delegate_trampoline (MonoClass *klass)
622 return arch_create_delegate_trampoline (mono_domain_get (), klass);
625 static MonoFreeMethodFunc default_mono_free_method = NULL;
628 * mono_install_free_method:
629 * @func: pointer to the MonoFreeMethodFunc used to release a method
631 * This is an internal VM routine, it is used for the engines to
632 * register a handler to release the resources associated with a method.
634 * Methods are freed when no more references to the delegate that holds
638 mono_install_free_method (MonoFreeMethodFunc func)
640 default_mono_free_method = func;
644 * mono_runtime_free_method:
645 * @domain; domain where the method is hosted
646 * @method: method to release
648 * This routine is invoked to free the resources associated with
649 * a method that has been JIT compiled. This is used to discard
650 * methods that were used only temporarily (for example, used in marshalling)
654 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
656 if (default_mono_free_method != NULL)
657 default_mono_free_method (domain, method);
659 mono_method_clear_object (domain, method);
661 mono_free_method (method);
665 * The vtables in the root appdomain are assumed to be reachable by other
666 * roots, and we don't use typed allocation in the other domains.
669 /* The sync block is no longer a GC pointer */
670 #define GC_HEADER_BITMAP (0)
672 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
675 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
677 MonoClassField *field;
683 max_size = mono_class_data_size (class) / sizeof (gpointer);
685 max_size = class->instance_size / sizeof (gpointer);
686 if (max_size > size) {
687 g_assert (offset <= 0);
688 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
693 /*An Ephemeron cannot be marked by sgen*/
694 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
696 memset (bitmap, 0, size / 8);
701 for (p = class; p != NULL; p = p->parent) {
702 gpointer iter = NULL;
703 while ((field = mono_class_get_fields (p, &iter))) {
707 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
709 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
712 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
715 /* FIXME: should not happen, flag as type load error */
716 if (field->type->byref)
719 if (static_fields && field->offset == -1)
723 pos = field->offset / sizeof (gpointer);
726 type = mono_type_get_underlying_type (field->type);
727 switch (type->type) {
730 case MONO_TYPE_FNPTR:
732 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
737 if (class->image != mono_defaults.corlib)
740 case MONO_TYPE_STRING:
741 case MONO_TYPE_SZARRAY:
742 case MONO_TYPE_CLASS:
743 case MONO_TYPE_OBJECT:
744 case MONO_TYPE_ARRAY:
745 g_assert ((field->offset % sizeof(gpointer)) == 0);
747 g_assert (pos < size || pos <= max_size);
748 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
749 *max_set = MAX (*max_set, pos);
751 case MONO_TYPE_GENERICINST:
752 if (!mono_type_generic_inst_is_valuetype (type)) {
753 g_assert ((field->offset % sizeof(gpointer)) == 0);
755 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
756 *max_set = MAX (*max_set, pos);
761 case MONO_TYPE_VALUETYPE: {
762 MonoClass *fclass = mono_class_from_mono_type (field->type);
763 if (fclass->has_references) {
764 /* remove the object header */
765 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
779 case MONO_TYPE_BOOLEAN:
783 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
794 * mono_class_compute_bitmap:
796 * Mono internal function to compute a bitmap of reference fields in a class.
799 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
801 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
806 * similar to the above, but sets the bits in the bitmap for any non-ref field
807 * and ignores static fields
810 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
812 MonoClassField *field;
817 max_size = class->instance_size / sizeof (gpointer);
818 if (max_size >= size) {
819 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
822 for (p = class; p != NULL; p = p->parent) {
823 gpointer iter = NULL;
824 while ((field = mono_class_get_fields (p, &iter))) {
827 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
829 /* FIXME: should not happen, flag as type load error */
830 if (field->type->byref)
833 pos = field->offset / sizeof (gpointer);
836 type = mono_type_get_underlying_type (field->type);
837 switch (type->type) {
838 #if SIZEOF_VOID_P == 8
842 case MONO_TYPE_FNPTR:
847 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
848 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
849 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
852 #if SIZEOF_VOID_P == 4
856 case MONO_TYPE_FNPTR:
861 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
862 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
863 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
869 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
870 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
871 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
874 case MONO_TYPE_BOOLEAN:
877 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
879 case MONO_TYPE_STRING:
880 case MONO_TYPE_SZARRAY:
881 case MONO_TYPE_CLASS:
882 case MONO_TYPE_OBJECT:
883 case MONO_TYPE_ARRAY:
885 case MONO_TYPE_GENERICINST:
886 if (!mono_type_generic_inst_is_valuetype (type)) {
891 case MONO_TYPE_VALUETYPE: {
892 MonoClass *fclass = mono_class_from_mono_type (field->type);
893 /* remove the object header */
894 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
898 g_assert_not_reached ();
907 * mono_class_insecure_overlapping:
908 * check if a class with explicit layout has references and non-references
909 * fields overlapping.
911 * Returns: TRUE if it is insecure to load the type.
914 mono_class_insecure_overlapping (MonoClass *klass)
918 gsize default_bitmap [4] = {0};
920 gsize default_nrbitmap [4] = {0};
921 int i, insecure = FALSE;
924 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
925 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
927 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
928 int idx = i % (sizeof (bitmap [0]) * 8);
929 if (bitmap [idx] & nrbitmap [idx]) {
934 if (bitmap != default_bitmap)
936 if (nrbitmap != default_nrbitmap)
939 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
947 mono_string_alloc (int length)
949 return mono_string_new_size (mono_domain_get (), length);
953 mono_class_compute_gc_descriptor (MonoClass *class)
957 gsize default_bitmap [4] = {0};
958 static gboolean gcj_inited = FALSE;
963 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
964 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
965 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
966 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
968 #ifdef HAVE_GC_GCJ_MALLOC
970 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
974 #ifdef GC_REDIRECT_TO_LOCAL
975 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
976 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
978 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
979 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
984 mono_loader_unlock ();
988 mono_class_init (class);
990 if (class->gc_descr_inited)
993 class->gc_descr_inited = TRUE;
994 class->gc_descr = GC_NO_DESCRIPTOR;
996 bitmap = default_bitmap;
997 if (class == mono_defaults.string_class) {
998 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
999 } else if (class->rank) {
1000 mono_class_compute_gc_descriptor (class->element_class);
1001 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
1003 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1004 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1005 class->name_space, class->name);*/
1007 /* remove the object header */
1008 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1009 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));
1010 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1011 class->name_space, class->name);*/
1012 if (bitmap != default_bitmap)
1016 /*static int count = 0;
1019 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1020 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1022 if (class->gc_descr == GC_NO_DESCRIPTOR)
1023 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1025 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1026 if (bitmap != default_bitmap)
1032 * field_is_special_static:
1033 * @fklass: The MonoClass to look up.
1034 * @field: The MonoClassField describing the field.
1036 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1037 * SPECIAL_STATIC_NONE otherwise.
1040 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1042 MonoCustomAttrInfo *ainfo;
1044 ainfo = mono_custom_attrs_from_field (fklass, field);
1047 for (i = 0; i < ainfo->num_attrs; ++i) {
1048 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1049 if (klass->image == mono_defaults.corlib) {
1050 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1051 mono_custom_attrs_free (ainfo);
1052 return SPECIAL_STATIC_THREAD;
1054 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1055 mono_custom_attrs_free (ainfo);
1056 return SPECIAL_STATIC_CONTEXT;
1060 mono_custom_attrs_free (ainfo);
1061 return SPECIAL_STATIC_NONE;
1064 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1065 #define mix(a,b,c) { \
1066 a -= c; a ^= rot(c, 4); c += b; \
1067 b -= a; b ^= rot(a, 6); a += c; \
1068 c -= b; c ^= rot(b, 8); b += a; \
1069 a -= c; a ^= rot(c,16); c += b; \
1070 b -= a; b ^= rot(a,19); a += c; \
1071 c -= b; c ^= rot(b, 4); b += a; \
1073 #define final(a,b,c) { \
1074 c ^= b; c -= rot(b,14); \
1075 a ^= c; a -= rot(c,11); \
1076 b ^= a; b -= rot(a,25); \
1077 c ^= b; c -= rot(b,16); \
1078 a ^= c; a -= rot(c,4); \
1079 b ^= a; b -= rot(a,14); \
1080 c ^= b; c -= rot(b,24); \
1084 * mono_method_get_imt_slot:
1086 * The IMT slot is embedded into AOTed code, so this must return the same value
1087 * for the same method across all executions. This means:
1088 * - pointers shouldn't be used as hash values.
1089 * - mono_metadata_str_hash () should be used for hashing strings.
1092 mono_method_get_imt_slot (MonoMethod *method)
1094 MonoMethodSignature *sig;
1096 guint32 *hashes_start, *hashes;
1100 /* This can be used to stress tests the collision code */
1104 * We do this to simplify generic sharing. It will hurt
1105 * performance in cases where a class implements two different
1106 * instantiations of the same generic interface.
1107 * The code in build_imt_slots () depends on this.
1109 if (method->is_inflated)
1110 method = ((MonoMethodInflated*)method)->declaring;
1112 sig = mono_method_signature (method);
1113 hashes_count = sig->param_count + 4;
1114 hashes_start = malloc (hashes_count * sizeof (guint32));
1115 hashes = hashes_start;
1117 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1118 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1119 method->klass->name_space, method->klass->name, method->name);
1122 /* Initialize hashes */
1123 hashes [0] = mono_metadata_str_hash (method->klass->name);
1124 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1125 hashes [2] = mono_metadata_str_hash (method->name);
1126 hashes [3] = mono_metadata_type_hash (sig->ret);
1127 for (i = 0; i < sig->param_count; i++) {
1128 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1131 /* Setup internal state */
1132 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1134 /* Handle most of the hashes */
1135 while (hashes_count > 3) {
1144 /* Handle the last 3 hashes (all the case statements fall through) */
1145 switch (hashes_count) {
1146 case 3 : c += hashes [2];
1147 case 2 : b += hashes [1];
1148 case 1 : a += hashes [0];
1150 case 0: /* nothing left to add */
1154 free (hashes_start);
1155 /* Report the result */
1156 return c % MONO_IMT_SIZE;
1165 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1166 guint32 imt_slot = mono_method_get_imt_slot (method);
1167 MonoImtBuilderEntry *entry;
1169 if (slot_num >= 0 && imt_slot != slot_num) {
1170 /* we build just a single imt slot and this is not it */
1174 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1175 entry->key = method;
1176 entry->value.vtable_slot = vtable_slot;
1177 entry->next = imt_builder [imt_slot];
1178 if (imt_builder [imt_slot] != NULL) {
1179 entry->children = imt_builder [imt_slot]->children + 1;
1180 if (entry->children == 1) {
1181 mono_stats.imt_slots_with_collisions++;
1182 *imt_collisions_bitmap |= (1 << imt_slot);
1185 entry->children = 0;
1186 mono_stats.imt_used_slots++;
1188 imt_builder [imt_slot] = entry;
1191 char *method_name = mono_method_full_name (method, TRUE);
1192 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1193 method, method_name, imt_slot, vtable_slot, entry->children);
1194 g_free (method_name);
1201 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1203 MonoMethod *method = e->key;
1204 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1208 method->klass->name_space,
1209 method->klass->name,
1212 printf (" * %s: NULL\n", message);
1218 compare_imt_builder_entries (const void *p1, const void *p2) {
1219 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1220 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1222 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1226 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1228 int count = end - start;
1229 int chunk_start = out_array->len;
1232 for (i = start; i < end; ++i) {
1233 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1234 item->key = sorted_array [i]->key;
1235 item->value = sorted_array [i]->value;
1236 item->has_target_code = sorted_array [i]->has_target_code;
1237 item->is_equals = TRUE;
1239 item->check_target_idx = out_array->len + 1;
1241 item->check_target_idx = 0;
1242 g_ptr_array_add (out_array, item);
1245 int middle = start + count / 2;
1246 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1248 item->key = sorted_array [middle]->key;
1249 item->is_equals = FALSE;
1250 g_ptr_array_add (out_array, item);
1251 imt_emit_ir (sorted_array, start, middle, out_array);
1252 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1258 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1259 int number_of_entries = entries->children + 1;
1260 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1261 GPtrArray *result = g_ptr_array_new ();
1262 MonoImtBuilderEntry *current_entry;
1265 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1266 sorted_array [i] = current_entry;
1268 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1270 /*for (i = 0; i < number_of_entries; i++) {
1271 print_imt_entry (" sorted array:", sorted_array [i], i);
1274 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1276 free (sorted_array);
1281 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1283 if (imt_builder_entry != NULL) {
1284 if (imt_builder_entry->children == 0 && !fail_tramp) {
1285 /* No collision, return the vtable slot contents */
1286 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1288 /* Collision, build the thunk */
1289 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1292 result = imt_thunk_builder (vtable, domain,
1293 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1294 for (i = 0; i < imt_ir->len; ++i)
1295 g_free (g_ptr_array_index (imt_ir, i));
1296 g_ptr_array_free (imt_ir, TRUE);
1308 static MonoImtBuilderEntry*
1309 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1312 * LOCKING: requires the loader and domain locks.
1316 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1320 guint32 imt_collisions_bitmap = 0;
1321 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1322 int method_count = 0;
1323 gboolean record_method_count_for_max_collisions = FALSE;
1324 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1327 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1329 for (i = 0; i < klass->interface_offsets_count; ++i) {
1330 MonoClass *iface = klass->interfaces_packed [i];
1331 int interface_offset = klass->interface_offsets_packed [i];
1332 int method_slot_in_interface, vt_slot;
1334 if (mono_class_has_variant_generic_params (iface))
1335 has_variant_iface = TRUE;
1337 mono_class_setup_methods (iface);
1338 vt_slot = interface_offset;
1339 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1342 if (slot_num >= 0 && iface->is_inflated) {
1344 * The imt slot of the method is the same as for its declaring method,
1345 * see the comment in mono_method_get_imt_slot (), so we can
1346 * avoid inflating methods which will be discarded by
1347 * add_imt_builder_entry anyway.
1349 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1350 if (mono_method_get_imt_slot (method) != slot_num) {
1355 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1356 if (method->is_generic) {
1357 has_generic_virtual = TRUE;
1362 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1363 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1368 if (extra_interfaces) {
1369 int interface_offset = klass->vtable_size;
1371 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1372 MonoClass* iface = list_item->data;
1373 int method_slot_in_interface;
1374 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1375 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1377 if (method->is_generic)
1378 has_generic_virtual = TRUE;
1379 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1381 interface_offset += iface->method.count;
1384 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1385 /* overwrite the imt slot only if we're building all the entries or if
1386 * we're building this specific one
1388 if (slot_num < 0 || i == slot_num) {
1389 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1392 if (imt_builder [i]) {
1393 MonoImtBuilderEntry *entry;
1395 /* Link entries with imt_builder [i] */
1396 for (entry = entries; entry->next; entry = entry->next) {
1398 MonoMethod *method = (MonoMethod*)entry->key;
1399 char *method_name = mono_method_full_name (method, TRUE);
1400 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1401 g_free (method_name);
1404 entry->next = imt_builder [i];
1405 entries->children += imt_builder [i]->children + 1;
1407 imt_builder [i] = entries;
1410 if (has_generic_virtual || has_variant_iface) {
1412 * There might be collisions later when the the thunk is expanded.
1414 imt_collisions_bitmap |= (1 << i);
1417 * The IMT thunk might be called with an instance of one of the
1418 * generic virtual methods, so has to fallback to the IMT trampoline.
1420 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1422 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1425 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1429 if (imt_builder [i] != NULL) {
1430 int methods_in_slot = imt_builder [i]->children + 1;
1431 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1432 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1433 record_method_count_for_max_collisions = TRUE;
1435 method_count += methods_in_slot;
1439 mono_stats.imt_number_of_methods += method_count;
1440 if (record_method_count_for_max_collisions) {
1441 mono_stats.imt_method_count_when_max_collisions = method_count;
1444 for (i = 0; i < MONO_IMT_SIZE; i++) {
1445 MonoImtBuilderEntry* entry = imt_builder [i];
1446 while (entry != NULL) {
1447 MonoImtBuilderEntry* next = entry->next;
1453 /* we OR the bitmap since we may build just a single imt slot at a time */
1454 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1458 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1459 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1463 * mono_vtable_build_imt_slot:
1464 * @vtable: virtual object table struct
1465 * @imt_slot: slot in the IMT table
1467 * Fill the given @imt_slot in the IMT table of @vtable with
1468 * a trampoline or a thunk for the case of collisions.
1469 * This is part of the internal mono API.
1471 * LOCKING: Take the domain lock.
1474 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1476 gpointer *imt = (gpointer*)vtable;
1477 imt -= MONO_IMT_SIZE;
1478 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1480 /* no support for extra interfaces: the proxy objects will need
1481 * to build the complete IMT
1482 * Update and heck needs to ahppen inside the proper domain lock, as all
1483 * the changes made to a MonoVTable.
1485 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1486 mono_domain_lock (vtable->domain);
1487 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1488 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1489 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1490 mono_domain_unlock (vtable->domain);
1491 mono_loader_unlock ();
1496 * The first two free list entries both belong to the wait list: The
1497 * first entry is the pointer to the head of the list and the second
1498 * entry points to the last element. That way appending and removing
1499 * the first element are both O(1) operations.
1501 #ifdef MONO_SMALL_CONFIG
1502 #define NUM_FREE_LISTS 6
1504 #define NUM_FREE_LISTS 12
1506 #define FIRST_FREE_LIST_SIZE 64
1507 #define MAX_WAIT_LENGTH 50
1508 #define THUNK_THRESHOLD 10
1511 * LOCKING: The domain lock must be held.
1514 init_thunk_free_lists (MonoDomain *domain)
1516 if (domain->thunk_free_lists)
1518 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1522 list_index_for_size (int item_size)
1525 int size = FIRST_FREE_LIST_SIZE;
1527 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1536 * mono_method_alloc_generic_virtual_thunk:
1538 * @size: size in bytes
1540 * Allocs size bytes to be used for the code of a generic virtual
1541 * thunk. It's either allocated from the domain's code manager or
1542 * reused from a previously invalidated piece.
1544 * LOCKING: The domain lock must be held.
1547 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1549 static gboolean inited = FALSE;
1550 static int generic_virtual_thunks_size = 0;
1554 MonoThunkFreeList **l;
1556 init_thunk_free_lists (domain);
1558 size += sizeof (guint32);
1559 if (size < sizeof (MonoThunkFreeList))
1560 size = sizeof (MonoThunkFreeList);
1562 i = list_index_for_size (size);
1563 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1564 if ((*l)->size >= size) {
1565 MonoThunkFreeList *item = *l;
1567 return ((guint32*)item) + 1;
1571 /* no suitable item found - search lists of larger sizes */
1572 while (++i < NUM_FREE_LISTS) {
1573 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1576 g_assert (item->size > size);
1577 domain->thunk_free_lists [i] = item->next;
1578 return ((guint32*)item) + 1;
1581 /* still nothing found - allocate it */
1583 mono_counters_register ("Generic virtual thunk bytes",
1584 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1587 generic_virtual_thunks_size += size;
1589 p = mono_domain_code_reserve (domain, size);
1592 mono_domain_lock (domain);
1593 if (!domain->generic_virtual_thunks)
1594 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1595 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1596 mono_domain_unlock (domain);
1602 * LOCKING: The domain lock must be held.
1605 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1608 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1609 gboolean found = FALSE;
1611 mono_domain_lock (domain);
1612 if (!domain->generic_virtual_thunks)
1613 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1614 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1616 mono_domain_unlock (domain);
1619 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1621 init_thunk_free_lists (domain);
1623 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1624 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1625 int length = item->length;
1628 /* unlink the first item from the wait list */
1629 domain->thunk_free_lists [0] = item->next;
1630 domain->thunk_free_lists [0]->length = length - 1;
1632 i = list_index_for_size (item->size);
1634 /* put it in the free list */
1635 item->next = domain->thunk_free_lists [i];
1636 domain->thunk_free_lists [i] = item;
1640 if (domain->thunk_free_lists [1]) {
1641 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1642 domain->thunk_free_lists [0]->length++;
1644 g_assert (!domain->thunk_free_lists [0]);
1646 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1647 domain->thunk_free_lists [0]->length = 1;
1651 typedef struct _GenericVirtualCase {
1655 struct _GenericVirtualCase *next;
1656 } GenericVirtualCase;
1659 * get_generic_virtual_entries:
1661 * Return IMT entries for the generic virtual method instances and
1662 * variant interface methods for vtable slot
1665 static MonoImtBuilderEntry*
1666 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1668 GenericVirtualCase *list;
1669 MonoImtBuilderEntry *entries;
1671 mono_domain_lock (domain);
1672 if (!domain->generic_virtual_cases)
1673 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1675 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1678 for (; list; list = list->next) {
1679 MonoImtBuilderEntry *entry;
1681 if (list->count < THUNK_THRESHOLD)
1684 entry = g_new0 (MonoImtBuilderEntry, 1);
1685 entry->key = list->method;
1686 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1687 entry->has_target_code = 1;
1689 entry->children = entries->children + 1;
1690 entry->next = entries;
1694 mono_domain_unlock (domain);
1696 /* FIXME: Leaking memory ? */
1701 * mono_method_add_generic_virtual_invocation:
1703 * @vtable_slot: pointer to the vtable slot
1704 * @method: the inflated generic virtual method
1705 * @code: the method's code
1707 * Registers a call via unmanaged code to a generic virtual method
1708 * instantiation or variant interface method. If the number of calls reaches a threshold
1709 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1710 * virtual method thunk.
1713 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1714 gpointer *vtable_slot,
1715 MonoMethod *method, gpointer code)
1717 static gboolean inited = FALSE;
1718 static int num_added = 0;
1720 GenericVirtualCase *gvc, *list;
1721 MonoImtBuilderEntry *entries;
1725 mono_domain_lock (domain);
1726 if (!domain->generic_virtual_cases)
1727 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1729 /* Check whether the case was already added */
1730 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1733 if (gvc->method == method)
1738 /* If not found, make a new one */
1740 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1741 gvc->method = method;
1744 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1746 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1749 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1755 if (++gvc->count == THUNK_THRESHOLD) {
1756 gpointer *old_thunk = *vtable_slot;
1757 gpointer vtable_trampoline = NULL;
1758 gpointer imt_trampoline = NULL;
1760 if ((gpointer)vtable_slot < (gpointer)vtable) {
1761 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1762 int imt_slot = MONO_IMT_SIZE + displacement;
1764 /* Force the rebuild of the thunk at the next call */
1765 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1766 *vtable_slot = imt_trampoline;
1768 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1770 entries = get_generic_virtual_entries (domain, vtable_slot);
1772 sorted = imt_sort_slot_entries (entries);
1774 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1778 MonoImtBuilderEntry *next = entries->next;
1783 for (i = 0; i < sorted->len; ++i)
1784 g_free (g_ptr_array_index (sorted, i));
1785 g_ptr_array_free (sorted, TRUE);
1788 #ifndef __native_client__
1789 /* We don't re-use any thunks as there is a lot of overhead */
1790 /* to deleting and re-using code in Native Client. */
1791 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1792 invalidate_generic_virtual_thunk (domain, old_thunk);
1796 mono_domain_unlock (domain);
1799 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1802 * mono_class_vtable:
1803 * @domain: the application domain
1804 * @class: the class to initialize
1806 * VTables are domain specific because we create domain specific code, and
1807 * they contain the domain specific static class data.
1808 * On failure, NULL is returned, and class->exception_type is set.
1811 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1813 return mono_class_vtable_full (domain, class, FALSE);
1817 * mono_class_vtable_full:
1818 * @domain: the application domain
1819 * @class: the class to initialize
1820 * @raise_on_error if an exception should be raised on failure or not
1822 * VTables are domain specific because we create domain specific code, and
1823 * they contain the domain specific static class data.
1826 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1828 MonoClassRuntimeInfo *runtime_info;
1832 if (class->exception_type) {
1834 mono_raise_exception (mono_class_get_exception_for_failure (class));
1838 /* this check can be inlined in jitted code, too */
1839 runtime_info = class->runtime_info;
1840 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1841 return runtime_info->domain_vtables [domain->domain_id];
1842 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1846 * mono_class_try_get_vtable:
1847 * @domain: the application domain
1848 * @class: the class to initialize
1850 * This function tries to get the associated vtable from @class if
1851 * it was already created.
1854 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1856 MonoClassRuntimeInfo *runtime_info;
1860 runtime_info = class->runtime_info;
1861 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1862 return runtime_info->domain_vtables [domain->domain_id];
1867 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1869 size_t alloc_offset;
1872 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1873 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1874 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1876 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1877 g_assert ((imt_table_bytes & 7) == 4);
1884 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1888 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1891 MonoClassRuntimeInfo *runtime_info, *old_info;
1892 MonoClassField *field;
1894 int i, vtable_slots;
1895 size_t imt_table_bytes;
1897 guint32 vtable_size, class_size;
1899 gpointer *interface_offsets;
1901 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1902 mono_domain_lock (domain);
1903 runtime_info = class->runtime_info;
1904 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1905 mono_domain_unlock (domain);
1906 mono_loader_unlock ();
1907 return runtime_info->domain_vtables [domain->domain_id];
1909 if (!class->inited || class->exception_type) {
1910 if (!mono_class_init (class) || class->exception_type) {
1911 mono_domain_unlock (domain);
1912 mono_loader_unlock ();
1914 mono_raise_exception (mono_class_get_exception_for_failure (class));
1919 /* Array types require that their element type be valid*/
1920 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1921 MonoClass *element_class = class->element_class;
1922 if (!element_class->inited)
1923 mono_class_init (element_class);
1925 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1926 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1927 mono_class_setup_vtable (element_class);
1929 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1930 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1931 if (class->exception_type == MONO_EXCEPTION_NONE)
1932 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1933 mono_domain_unlock (domain);
1934 mono_loader_unlock ();
1936 mono_raise_exception (mono_class_get_exception_for_failure (class));
1942 * For some classes, mono_class_init () already computed class->vtable_size, and
1943 * that is all that is needed because of the vtable trampolines.
1945 if (!class->vtable_size)
1946 mono_class_setup_vtable (class);
1948 if (class->generic_class && !class->vtable)
1949 mono_class_check_vtable_constraints (class, NULL);
1951 /* Initialize klass->has_finalize */
1952 mono_class_has_finalizer (class);
1954 if (class->exception_type) {
1955 mono_domain_unlock (domain);
1956 mono_loader_unlock ();
1958 mono_raise_exception (mono_class_get_exception_for_failure (class));
1962 vtable_slots = class->vtable_size;
1963 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1964 class_size = mono_class_data_size (class);
1969 if (class->interface_offsets_count) {
1970 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1971 mono_stats.imt_number_of_tables++;
1972 mono_stats.imt_tables_size += imt_table_bytes;
1974 imt_table_bytes = 0;
1977 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1980 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1982 mono_stats.used_class_count++;
1983 mono_stats.class_vtable_size += vtable_size;
1985 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1986 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1987 g_assert (!((gsize)vt & 7));
1990 vt->rank = class->rank;
1991 vt->domain = domain;
1993 mono_class_compute_gc_descriptor (class);
1995 * We can't use typed allocation in the non-root domains, since the
1996 * collector needs the GC descriptor stored in the vtable even after
1997 * the mempool containing the vtable is destroyed when the domain is
1998 * unloaded. An alternative might be to allocate vtables in the GC
1999 * heap, but this does not seem to work (it leads to crashes inside
2000 * libgc). If that approach is tried, two gc descriptors need to be
2001 * allocated for each class: one for the root domain, and one for all
2002 * other domains. The second descriptor should contain a bit for the
2003 * vtable field in MonoObject, since we can no longer assume the
2004 * vtable is reachable by other roots after the appdomain is unloaded.
2006 #ifdef HAVE_BOEHM_GC
2007 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2008 vt->gc_descr = GC_NO_DESCRIPTOR;
2011 vt->gc_descr = class->gc_descr;
2013 gc_bits = mono_gc_get_vtable_bits (class);
2014 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2016 vt->gc_bits = gc_bits;
2019 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2020 if (class->has_static_refs) {
2021 gpointer statics_gc_descr;
2023 gsize default_bitmap [4] = {0};
2026 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2027 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2028 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2029 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2030 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2031 if (bitmap != default_bitmap)
2034 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2036 vt->has_static_fields = TRUE;
2037 mono_stats.class_static_data_size += class_size;
2041 while ((field = mono_class_get_fields (class, &iter))) {
2042 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2044 if (mono_field_is_deleted (field))
2046 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2047 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2048 if (special_static != SPECIAL_STATIC_NONE) {
2049 guint32 size, offset;
2051 gsize default_bitmap [4] = {0};
2056 if (mono_type_is_reference (field->type)) {
2057 default_bitmap [0] = 1;
2059 bitmap = default_bitmap;
2060 } else if (mono_type_is_struct (field->type)) {
2061 fclass = mono_class_from_mono_type (field->type);
2062 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2063 numbits = max_set + 1;
2065 default_bitmap [0] = 0;
2067 bitmap = default_bitmap;
2069 size = mono_type_size (field->type, &align);
2070 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2071 if (!domain->special_static_fields)
2072 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2073 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2074 if (bitmap != default_bitmap)
2077 * This marks the field as special static to speed up the
2078 * checks in mono_field_static_get/set_value ().
2084 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2085 MonoClass *fklass = mono_class_from_mono_type (field->type);
2086 const char *data = mono_field_get_data (field);
2088 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2089 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2090 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2093 if (fklass->valuetype) {
2094 memcpy (t, data, mono_class_value_size (fklass, NULL));
2096 /* it's a pointer type: add check */
2097 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2104 vt->max_interface_id = class->max_interface_id;
2105 vt->interface_bitmap = class->interface_bitmap;
2107 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2108 // class->name, class->interface_offsets_count);
2110 if (! ARCH_USE_IMT) {
2111 /* initialize interface offsets */
2112 for (i = 0; i < class->interface_offsets_count; ++i) {
2113 int interface_id = class->interfaces_packed [i]->interface_id;
2114 int slot = class->interface_offsets_packed [i];
2115 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2119 /* Initialize vtable */
2120 if (callbacks.get_vtable_trampoline) {
2121 // This also covers the AOT case
2122 for (i = 0; i < class->vtable_size; ++i) {
2123 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2126 mono_class_setup_vtable (class);
2128 for (i = 0; i < class->vtable_size; ++i) {
2131 if ((cm = class->vtable [i]))
2132 vt->vtable [i] = arch_create_jit_trampoline (cm);
2136 if (ARCH_USE_IMT && imt_table_bytes) {
2137 /* Now that the vtable is full, we can actually fill up the IMT */
2138 if (callbacks.get_imt_trampoline) {
2139 /* lazy construction of the IMT entries enabled */
2140 for (i = 0; i < MONO_IMT_SIZE; ++i)
2141 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2143 build_imt (class, vt, domain, interface_offsets, NULL);
2148 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2149 * re-acquire them and check if another thread has created the vtable in the meantime.
2151 /* Special case System.MonoType to avoid infinite recursion */
2152 if (class != mono_defaults.monotype_class) {
2153 /*FIXME check for OOM*/
2154 vt->type = mono_type_get_object (domain, &class->byval_arg);
2155 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2156 /* This is unregistered in
2157 unregister_vtable_reflection_type() in
2159 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2162 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2164 /* class_vtable_array keeps an array of created vtables
2166 g_ptr_array_add (domain->class_vtable_array, vt);
2167 /* class->runtime_info is protected by the loader lock, both when
2168 * it it enlarged and when it is stored info.
2172 * Store the vtable in class->runtime_info.
2173 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2175 mono_memory_barrier ();
2177 old_info = class->runtime_info;
2178 if (old_info && old_info->max_domain >= domain->domain_id) {
2179 /* someone already created a large enough runtime info */
2180 old_info->domain_vtables [domain->domain_id] = vt;
2182 int new_size = domain->domain_id;
2184 new_size = MAX (new_size, old_info->max_domain);
2186 /* make the new size a power of two */
2188 while (new_size > i)
2191 /* this is a bounded memory retention issue: may want to
2192 * handle it differently when we'll have a rcu-like system.
2194 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2195 runtime_info->max_domain = new_size - 1;
2196 /* copy the stuff from the older info */
2198 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2200 runtime_info->domain_vtables [domain->domain_id] = vt;
2202 mono_memory_barrier ();
2203 class->runtime_info = runtime_info;
2206 if (class == mono_defaults.monotype_class) {
2207 /*FIXME check for OOM*/
2208 vt->type = mono_type_get_object (domain, &class->byval_arg);
2209 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2210 /* This is unregistered in
2211 unregister_vtable_reflection_type() in
2213 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2216 mono_domain_unlock (domain);
2217 mono_loader_unlock ();
2219 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2220 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2221 mono_raise_exception (mono_class_get_exception_for_failure (class));
2223 /* make sure the parent is initialized */
2224 /*FIXME shouldn't this fail the current type?*/
2226 mono_class_vtable_full (domain, class->parent, raise_on_error);
2231 #ifndef DISABLE_REMOTING
2233 * mono_class_proxy_vtable:
2234 * @domain: the application domain
2235 * @remove_class: the remote class
2237 * Creates a vtable for transparent proxies. It is basically
2238 * a copy of the real vtable of the class wrapped in @remote_class,
2239 * but all function pointers invoke the remoting functions, and
2240 * vtable->klass points to the transparent proxy class, and not to @class.
2243 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2246 MonoVTable *vt, *pvt;
2247 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2249 GSList *extra_interfaces = NULL;
2250 MonoClass *class = remote_class->proxy_class;
2251 gpointer *interface_offsets;
2254 size_t imt_table_bytes;
2256 #ifdef COMPRESSED_INTERFACE_BITMAP
2260 vt = mono_class_vtable (domain, class);
2261 g_assert (vt); /*FIXME property handle failure*/
2262 max_interface_id = vt->max_interface_id;
2264 /* Calculate vtable space for extra interfaces */
2265 for (j = 0; j < remote_class->interface_count; j++) {
2266 MonoClass* iclass = remote_class->interfaces[j];
2270 /*FIXME test for interfaces with variant generic arguments*/
2271 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2272 continue; /* interface implemented by the class */
2273 if (g_slist_find (extra_interfaces, iclass))
2276 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2278 method_count = mono_class_num_methods (iclass);
2280 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2281 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2283 for (i = 0; i < ifaces->len; ++i) {
2284 MonoClass *ic = g_ptr_array_index (ifaces, i);
2285 /*FIXME test for interfaces with variant generic arguments*/
2286 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2287 continue; /* interface implemented by the class */
2288 if (g_slist_find (extra_interfaces, ic))
2290 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2291 method_count += mono_class_num_methods (ic);
2293 g_ptr_array_free (ifaces, TRUE);
2296 extra_interface_vtsize += method_count * sizeof (gpointer);
2297 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2301 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2302 mono_stats.imt_number_of_tables++;
2303 mono_stats.imt_tables_size += imt_table_bytes;
2305 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2308 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2310 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2312 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2313 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2314 g_assert (!((gsize)pvt & 7));
2316 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2318 pvt->klass = mono_defaults.transparent_proxy_class;
2319 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2320 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2322 /* initialize vtable */
2323 mono_class_setup_vtable (class);
2324 for (i = 0; i < class->vtable_size; ++i) {
2327 if ((cm = class->vtable [i]))
2328 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2330 pvt->vtable [i] = NULL;
2333 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2334 /* create trampolines for abstract methods */
2335 for (k = class; k; k = k->parent) {
2337 gpointer iter = NULL;
2338 while ((m = mono_class_get_methods (k, &iter)))
2339 if (!pvt->vtable [m->slot])
2340 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2344 pvt->max_interface_id = max_interface_id;
2345 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2346 #ifdef COMPRESSED_INTERFACE_BITMAP
2347 bitmap = g_malloc0 (bsize);
2349 bitmap = mono_domain_alloc0 (domain, bsize);
2352 if (! ARCH_USE_IMT) {
2353 /* initialize interface offsets */
2354 for (i = 0; i < class->interface_offsets_count; ++i) {
2355 int interface_id = class->interfaces_packed [i]->interface_id;
2356 int slot = class->interface_offsets_packed [i];
2357 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2360 for (i = 0; i < class->interface_offsets_count; ++i) {
2361 int interface_id = class->interfaces_packed [i]->interface_id;
2362 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2365 if (extra_interfaces) {
2366 int slot = class->vtable_size;
2372 /* Create trampolines for the methods of the interfaces */
2373 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2374 interf = list_item->data;
2376 if (! ARCH_USE_IMT) {
2377 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2379 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2383 while ((cm = mono_class_get_methods (interf, &iter)))
2384 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2386 slot += mono_class_num_methods (interf);
2388 if (! ARCH_USE_IMT) {
2389 g_slist_free (extra_interfaces);
2394 /* Now that the vtable is full, we can actually fill up the IMT */
2395 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2396 if (extra_interfaces) {
2397 g_slist_free (extra_interfaces);
2401 #ifdef COMPRESSED_INTERFACE_BITMAP
2402 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2403 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2404 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2407 pvt->interface_bitmap = bitmap;
2412 #endif /* DISABLE_REMOTING */
2415 * mono_class_field_is_special_static:
2417 * Returns whether @field is a thread/context static field.
2420 mono_class_field_is_special_static (MonoClassField *field)
2422 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2424 if (mono_field_is_deleted (field))
2426 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2427 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2434 * mono_class_field_get_special_static_type:
2435 * @field: The MonoClassField describing the field.
2437 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2438 * SPECIAL_STATIC_NONE otherwise.
2441 mono_class_field_get_special_static_type (MonoClassField *field)
2443 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2444 return SPECIAL_STATIC_NONE;
2445 if (mono_field_is_deleted (field))
2446 return SPECIAL_STATIC_NONE;
2447 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2448 return field_is_special_static (field->parent, field);
2449 return SPECIAL_STATIC_NONE;
2453 * mono_class_has_special_static_fields:
2455 * Returns whenever @klass has any thread/context static fields.
2458 mono_class_has_special_static_fields (MonoClass *klass)
2460 MonoClassField *field;
2464 while ((field = mono_class_get_fields (klass, &iter))) {
2465 g_assert (field->parent == klass);
2466 if (mono_class_field_is_special_static (field))
2473 #ifndef DISABLE_REMOTING
2475 * create_remote_class_key:
2476 * Creates an array of pointers that can be used as a hash key for a remote class.
2477 * The first element of the array is the number of pointers.
2480 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2485 if (remote_class == NULL) {
2486 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2487 key = g_malloc (sizeof(gpointer) * 3);
2488 key [0] = GINT_TO_POINTER (2);
2489 key [1] = mono_defaults.marshalbyrefobject_class;
2490 key [2] = extra_class;
2492 key = g_malloc (sizeof(gpointer) * 2);
2493 key [0] = GINT_TO_POINTER (1);
2494 key [1] = extra_class;
2497 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2498 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2499 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2500 key [1] = remote_class->proxy_class;
2502 // Keep the list of interfaces sorted
2503 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2504 if (extra_class && remote_class->interfaces [i] > extra_class) {
2505 key [j++] = extra_class;
2508 key [j] = remote_class->interfaces [i];
2511 key [j] = extra_class;
2513 // Replace the old class. The interface list is the same
2514 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2515 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2516 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2517 for (i = 0; i < remote_class->interface_count; i++)
2518 key [2 + i] = remote_class->interfaces [i];
2526 * copy_remote_class_key:
2528 * Make a copy of KEY in the domain and return the copy.
2531 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2533 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2534 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2536 memcpy (mp_key, key, key_size);
2542 * mono_remote_class:
2543 * @domain: the application domain
2544 * @class_name: name of the remote class
2546 * Creates and initializes a MonoRemoteClass object for a remote type.
2548 * Can raise an exception on failure.
2551 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2554 MonoRemoteClass *rc;
2555 gpointer* key, *mp_key;
2558 key = create_remote_class_key (NULL, proxy_class);
2560 mono_domain_lock (domain);
2561 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2565 mono_domain_unlock (domain);
2569 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2570 if (!mono_error_ok (&error)) {
2572 mono_domain_unlock (domain);
2573 mono_error_raise_exception (&error);
2576 mp_key = copy_remote_class_key (domain, key);
2580 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2581 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2582 rc->interface_count = 1;
2583 rc->interfaces [0] = proxy_class;
2584 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2586 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2587 rc->interface_count = 0;
2588 rc->proxy_class = proxy_class;
2591 rc->default_vtable = NULL;
2592 rc->xdomain_vtable = NULL;
2593 rc->proxy_class_name = name;
2594 #ifndef DISABLE_PERFCOUNTERS
2595 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2598 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2600 mono_domain_unlock (domain);
2605 * clone_remote_class:
2606 * Creates a copy of the remote_class, adding the provided class or interface
2608 static MonoRemoteClass*
2609 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2611 MonoRemoteClass *rc;
2612 gpointer* key, *mp_key;
2614 key = create_remote_class_key (remote_class, extra_class);
2615 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2621 mp_key = copy_remote_class_key (domain, key);
2625 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2627 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2628 rc->proxy_class = remote_class->proxy_class;
2629 rc->interface_count = remote_class->interface_count + 1;
2631 // Keep the list of interfaces sorted, since the hash key of
2632 // the remote class depends on this
2633 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2634 if (remote_class->interfaces [i] > extra_class && i == j)
2635 rc->interfaces [j++] = extra_class;
2636 rc->interfaces [j] = remote_class->interfaces [i];
2639 rc->interfaces [j] = extra_class;
2641 // Replace the old class. The interface array is the same
2642 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2643 rc->proxy_class = extra_class;
2644 rc->interface_count = remote_class->interface_count;
2645 if (rc->interface_count > 0)
2646 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2649 rc->default_vtable = NULL;
2650 rc->xdomain_vtable = NULL;
2651 rc->proxy_class_name = remote_class->proxy_class_name;
2653 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2659 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2661 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2662 mono_domain_lock (domain);
2663 if (rp->target_domain_id != -1) {
2664 if (remote_class->xdomain_vtable == NULL)
2665 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2666 mono_domain_unlock (domain);
2667 mono_loader_unlock ();
2668 return remote_class->xdomain_vtable;
2670 if (remote_class->default_vtable == NULL) {
2673 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2674 klass = mono_class_from_mono_type (type);
2676 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)))
2677 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2680 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2683 mono_domain_unlock (domain);
2684 mono_loader_unlock ();
2685 return remote_class->default_vtable;
2689 * mono_upgrade_remote_class:
2690 * @domain: the application domain
2691 * @tproxy: the proxy whose remote class has to be upgraded.
2692 * @klass: class to which the remote class can be casted.
2694 * Updates the vtable of the remote class by adding the necessary method slots
2695 * and interface offsets so it can be safely casted to klass. klass can be a
2696 * class or an interface.
2699 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2701 MonoTransparentProxy *tproxy;
2702 MonoRemoteClass *remote_class;
2703 gboolean redo_vtable;
2705 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2706 mono_domain_lock (domain);
2708 tproxy = (MonoTransparentProxy*) proxy_object;
2709 remote_class = tproxy->remote_class;
2711 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2714 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2715 if (remote_class->interfaces [i] == klass)
2716 redo_vtable = FALSE;
2719 redo_vtable = (remote_class->proxy_class != klass);
2723 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2724 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2727 mono_domain_unlock (domain);
2728 mono_loader_unlock ();
2730 #endif /* DISABLE_REMOTING */
2734 * mono_object_get_virtual_method:
2735 * @obj: object to operate on.
2738 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2739 * the instance of a callvirt of method.
2742 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2745 MonoMethod **vtable;
2746 gboolean is_proxy = FALSE;
2747 MonoMethod *res = NULL;
2749 klass = mono_object_class (obj);
2750 #ifndef DISABLE_REMOTING
2751 if (klass == mono_defaults.transparent_proxy_class) {
2752 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2757 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2760 mono_class_setup_vtable (klass);
2761 vtable = klass->vtable;
2763 if (method->slot == -1) {
2764 /* method->slot might not be set for instances of generic methods */
2765 if (method->is_inflated) {
2766 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2767 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2770 g_assert_not_reached ();
2774 /* check method->slot is a valid index: perform isinstance? */
2775 if (method->slot != -1) {
2776 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2778 gboolean variance_used = FALSE;
2779 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2780 g_assert (iface_offset > 0);
2781 res = vtable [iface_offset + method->slot];
2784 res = vtable [method->slot];
2788 #ifndef DISABLE_REMOTING
2790 /* It may be an interface, abstract class method or generic method */
2791 if (!res || mono_method_signature (res)->generic_param_count)
2794 /* generic methods demand invoke_with_check */
2795 if (mono_method_signature (res)->generic_param_count)
2796 res = mono_marshal_get_remoting_invoke_with_check (res);
2799 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2800 res = mono_cominterop_get_invoke (res);
2803 res = mono_marshal_get_remoting_invoke (res);
2808 if (method->is_inflated) {
2810 /* Have to inflate the result */
2811 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2812 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2822 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2824 g_error ("runtime invoke called on uninitialized runtime");
2828 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2831 * mono_runtime_invoke:
2832 * @method: method to invoke
2833 * @obJ: object instance
2834 * @params: arguments to the method
2835 * @exc: exception information.
2837 * Invokes the method represented by @method on the object @obj.
2839 * obj is the 'this' pointer, it should be NULL for static
2840 * methods, a MonoObject* for object instances and a pointer to
2841 * the value type for value types.
2843 * The params array contains the arguments to the method with the
2844 * same convention: MonoObject* pointers for object instances and
2845 * pointers to the value type otherwise.
2847 * From unmanaged code you'll usually use the
2848 * mono_runtime_invoke() variant.
2850 * Note that this function doesn't handle virtual methods for
2851 * you, it will exec the exact method you pass: we still need to
2852 * expose a function to lookup the derived class implementation
2853 * of a virtual method (there are examples of this in the code,
2856 * You can pass NULL as the exc argument if you don't want to
2857 * catch exceptions, otherwise, *exc will be set to the exception
2858 * thrown, if any. if an exception is thrown, you can't use the
2859 * MonoObject* result from the function.
2861 * If the method returns a value type, it is boxed in an object
2865 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2869 if (mono_runtime_get_no_exec ())
2870 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2872 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2873 mono_profiler_method_start_invoke (method);
2875 result = default_mono_runtime_invoke (method, obj, params, exc);
2877 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2878 mono_profiler_method_end_invoke (method);
2884 * mono_method_get_unmanaged_thunk:
2885 * @method: method to generate a thunk for.
2887 * Returns an unmanaged->managed thunk that can be used to call
2888 * a managed method directly from C.
2890 * The thunk's C signature closely matches the managed signature:
2892 * C#: public bool Equals (object obj);
2893 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2894 * MonoObject*, MonoException**);
2896 * The 1st ("this") parameter must not be used with static methods:
2898 * C#: public static bool ReferenceEquals (object a, object b);
2899 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2902 * The last argument must be a non-null pointer of a MonoException* pointer.
2903 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2904 * exception has been thrown in managed code. Otherwise it will point
2905 * to the MonoException* caught by the thunk. In this case, the result of
2906 * the thunk is undefined:
2908 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2909 * MonoException *ex = NULL;
2910 * Equals func = mono_method_get_unmanaged_thunk (method);
2911 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2913 * // handle exception
2916 * The calling convention of the thunk matches the platform's default
2917 * convention. This means that under Windows, C declarations must
2918 * contain the __stdcall attribute:
2920 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2921 * MonoObject*, MonoException**);
2925 * Value type arguments and return values are treated as they were objects:
2927 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2928 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2930 * Arguments must be properly boxed upon trunk's invocation, while return
2931 * values must be unboxed.
2934 mono_method_get_unmanaged_thunk (MonoMethod *method)
2936 method = mono_marshal_get_thunk_invoke_wrapper (method);
2937 return mono_compile_method (method);
2941 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2945 /* object fields cannot be byref, so we don't need a
2947 gpointer *p = (gpointer*)dest;
2954 case MONO_TYPE_BOOLEAN:
2956 case MONO_TYPE_U1: {
2957 guint8 *p = (guint8*)dest;
2958 *p = value ? *(guint8*)value : 0;
2963 case MONO_TYPE_CHAR: {
2964 guint16 *p = (guint16*)dest;
2965 *p = value ? *(guint16*)value : 0;
2968 #if SIZEOF_VOID_P == 4
2973 case MONO_TYPE_U4: {
2974 gint32 *p = (gint32*)dest;
2975 *p = value ? *(gint32*)value : 0;
2978 #if SIZEOF_VOID_P == 8
2983 case MONO_TYPE_U8: {
2984 gint64 *p = (gint64*)dest;
2985 *p = value ? *(gint64*)value : 0;
2988 case MONO_TYPE_R4: {
2989 float *p = (float*)dest;
2990 *p = value ? *(float*)value : 0;
2993 case MONO_TYPE_R8: {
2994 double *p = (double*)dest;
2995 *p = value ? *(double*)value : 0;
2998 case MONO_TYPE_STRING:
2999 case MONO_TYPE_SZARRAY:
3000 case MONO_TYPE_CLASS:
3001 case MONO_TYPE_OBJECT:
3002 case MONO_TYPE_ARRAY:
3003 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
3005 case MONO_TYPE_FNPTR:
3006 case MONO_TYPE_PTR: {
3007 gpointer *p = (gpointer*)dest;
3008 *p = deref_pointer? *(gpointer*)value: value;
3011 case MONO_TYPE_VALUETYPE:
3012 /* note that 't' and 'type->type' can be different */
3013 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3014 t = mono_class_enum_basetype (type->data.klass)->type;
3017 MonoClass *class = mono_class_from_mono_type (type);
3018 int size = mono_class_value_size (class, NULL);
3020 mono_gc_bzero_atomic (dest, size);
3022 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3025 case MONO_TYPE_GENERICINST:
3026 t = type->data.generic_class->container_class->byval_arg.type;
3029 g_error ("got type %x", type->type);
3034 * mono_field_set_value:
3035 * @obj: Instance object
3036 * @field: MonoClassField describing the field to set
3037 * @value: The value to be set
3039 * Sets the value of the field described by @field in the object instance @obj
3040 * to the value passed in @value. This method should only be used for instance
3041 * fields. For static fields, use mono_field_static_set_value.
3043 * The value must be on the native format of the field type.
3046 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3050 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3052 dest = (char*)obj + field->offset;
3053 mono_copy_value (field->type, dest, value, FALSE);
3057 * mono_field_static_set_value:
3058 * @field: MonoClassField describing the field to set
3059 * @value: The value to be set
3061 * Sets the value of the static field described by @field
3062 * to the value passed in @value.
3064 * The value must be on the native format of the field type.
3067 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3071 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3072 /* you cant set a constant! */
3073 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3075 if (field->offset == -1) {
3076 /* Special static */
3079 mono_domain_lock (vt->domain);
3080 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3081 mono_domain_unlock (vt->domain);
3082 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3084 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3086 mono_copy_value (field->type, dest, value, FALSE);
3090 * mono_vtable_get_static_field_data:
3092 * Internal use function: return a pointer to the memory holding the static fields
3093 * for a class or NULL if there are no static fields.
3094 * This is exported only for use by the debugger.
3097 mono_vtable_get_static_field_data (MonoVTable *vt)
3099 if (!vt->has_static_fields)
3101 return vt->vtable [vt->klass->vtable_size];
3105 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3109 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3110 if (field->offset == -1) {
3111 /* Special static */
3114 mono_domain_lock (vt->domain);
3115 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3116 mono_domain_unlock (vt->domain);
3117 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3119 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3122 src = (guint8*)obj + field->offset;
3129 * mono_field_get_value:
3130 * @obj: Object instance
3131 * @field: MonoClassField describing the field to fetch information from
3132 * @value: pointer to the location where the value will be stored
3134 * Use this routine to get the value of the field @field in the object
3137 * The pointer provided by value must be of the field type, for reference
3138 * types this is a MonoObject*, for value types its the actual pointer to
3143 * mono_field_get_value (obj, int_field, &i);
3146 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3152 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3154 src = (char*)obj + field->offset;
3155 mono_copy_value (field->type, value, src, TRUE);
3159 * mono_field_get_value_object:
3160 * @domain: domain where the object will be created (if boxing)
3161 * @field: MonoClassField describing the field to fetch information from
3162 * @obj: The object instance for the field.
3164 * Returns: a new MonoObject with the value from the given field. If the
3165 * field represents a value type, the value is boxed.
3169 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3173 MonoVTable *vtable = NULL;
3175 gboolean is_static = FALSE;
3176 gboolean is_ref = FALSE;
3177 gboolean is_literal = FALSE;
3178 gboolean is_ptr = FALSE;
3180 MonoType *type = mono_field_get_type_checked (field, &error);
3182 if (!mono_error_ok (&error))
3183 mono_error_raise_exception (&error);
3185 switch (type->type) {
3186 case MONO_TYPE_STRING:
3187 case MONO_TYPE_OBJECT:
3188 case MONO_TYPE_CLASS:
3189 case MONO_TYPE_ARRAY:
3190 case MONO_TYPE_SZARRAY:
3195 case MONO_TYPE_BOOLEAN:
3198 case MONO_TYPE_CHAR:
3207 case MONO_TYPE_VALUETYPE:
3208 is_ref = type->byref;
3210 case MONO_TYPE_GENERICINST:
3211 is_ref = !mono_type_generic_inst_is_valuetype (type);
3217 g_error ("type 0x%x not handled in "
3218 "mono_field_get_value_object", type->type);
3222 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3225 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3229 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3230 if (!vtable->initialized)
3231 mono_runtime_class_init (vtable);
3239 get_default_field_value (domain, field, &o);
3240 } else if (is_static) {
3241 mono_field_static_get_value (vtable, field, &o);
3243 mono_field_get_value (obj, field, &o);
3249 static MonoMethod *m;
3255 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3256 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3262 get_default_field_value (domain, field, v);
3263 } else if (is_static) {
3264 mono_field_static_get_value (vtable, field, v);
3266 mono_field_get_value (obj, field, v);
3269 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3270 args [0] = ptr ? *ptr : NULL;
3271 args [1] = mono_type_get_object (mono_domain_get (), type);
3273 return mono_runtime_invoke (m, NULL, args, NULL);
3276 /* boxed value type */
3277 klass = mono_class_from_mono_type (type);
3279 if (mono_class_is_nullable (klass))
3280 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3282 o = mono_object_new (domain, klass);
3283 v = ((gchar *) o) + sizeof (MonoObject);
3286 get_default_field_value (domain, field, v);
3287 } else if (is_static) {
3288 mono_field_static_get_value (vtable, field, v);
3290 mono_field_get_value (obj, field, v);
3297 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3300 const char *p = blob;
3301 mono_metadata_decode_blob_size (p, &p);
3304 case MONO_TYPE_BOOLEAN:
3307 *(guint8 *) value = *p;
3309 case MONO_TYPE_CHAR:
3312 *(guint16*) value = read16 (p);
3316 *(guint32*) value = read32 (p);
3320 *(guint64*) value = read64 (p);
3323 readr4 (p, (float*) value);
3326 readr8 (p, (double*) value);
3328 case MONO_TYPE_STRING:
3329 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3331 case MONO_TYPE_CLASS:
3332 *(gpointer*) value = NULL;
3336 g_warning ("type 0x%02x should not be in constant table", type);
3342 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3344 MonoTypeEnum def_type;
3347 data = mono_class_get_field_default_value (field, &def_type);
3348 mono_get_constant_value_from_blob (domain, def_type, data, value);
3352 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3356 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3358 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3359 get_default_field_value (vt->domain, field, value);
3363 if (field->offset == -1) {
3364 /* Special static */
3365 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3366 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3368 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3370 mono_copy_value (field->type, value, src, TRUE);
3374 * mono_field_static_get_value:
3375 * @vt: vtable to the object
3376 * @field: MonoClassField describing the field to fetch information from
3377 * @value: where the value is returned
3379 * Use this routine to get the value of the static field @field value.
3381 * The pointer provided by value must be of the field type, for reference
3382 * types this is a MonoObject*, for value types its the actual pointer to
3387 * mono_field_static_get_value (vt, int_field, &i);
3390 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3392 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3396 * mono_property_set_value:
3397 * @prop: MonoProperty to set
3398 * @obj: instance object on which to act
3399 * @params: parameters to pass to the propery
3400 * @exc: optional exception
3402 * Invokes the property's set method with the given arguments on the
3403 * object instance obj (or NULL for static properties).
3405 * You can pass NULL as the exc argument if you don't want to
3406 * catch exceptions, otherwise, *exc will be set to the exception
3407 * thrown, if any. if an exception is thrown, you can't use the
3408 * MonoObject* result from the function.
3411 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3413 default_mono_runtime_invoke (prop->set, obj, params, exc);
3417 * mono_property_get_value:
3418 * @prop: MonoProperty to fetch
3419 * @obj: instance object on which to act
3420 * @params: parameters to pass to the propery
3421 * @exc: optional exception
3423 * Invokes the property's get method with the given arguments on the
3424 * object instance obj (or NULL for static properties).
3426 * You can pass NULL as the exc argument if you don't want to
3427 * catch exceptions, otherwise, *exc will be set to the exception
3428 * thrown, if any. if an exception is thrown, you can't use the
3429 * MonoObject* result from the function.
3431 * Returns: the value from invoking the get method on the property.
3434 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3436 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3440 * mono_nullable_init:
3441 * @buf: The nullable structure to initialize.
3442 * @value: the value to initialize from
3443 * @klass: the type for the object
3445 * Initialize the nullable structure pointed to by @buf from @value which
3446 * should be a boxed value type. The size of @buf should be able to hold
3447 * as much data as the @klass->instance_size (which is the number of bytes
3448 * that will be copies).
3450 * Since Nullables have variable structure, we can not define a C
3451 * structure for them.
3454 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3456 MonoClass *param_class = klass->cast_class;
3458 mono_class_setup_fields_locking (klass);
3459 g_assert (klass->fields_inited);
3461 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3462 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3464 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3466 if (param_class->has_references)
3467 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3469 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3471 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3476 * mono_nullable_box:
3477 * @buf: The buffer representing the data to be boxed
3478 * @klass: the type to box it as.
3480 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3484 mono_nullable_box (guint8 *buf, MonoClass *klass)
3486 MonoClass *param_class = klass->cast_class;
3488 mono_class_setup_fields_locking (klass);
3489 g_assert (klass->fields_inited);
3491 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3492 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3494 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3495 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3496 if (param_class->has_references)
3497 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3499 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3507 * mono_get_delegate_invoke:
3508 * @klass: The delegate class
3510 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3513 mono_get_delegate_invoke (MonoClass *klass)
3517 /* This is called at runtime, so avoid the slower search in metadata */
3518 mono_class_setup_methods (klass);
3519 if (klass->exception_type)
3521 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3526 * mono_get_delegate_begin_invoke:
3527 * @klass: The delegate class
3529 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3532 mono_get_delegate_begin_invoke (MonoClass *klass)
3536 /* This is called at runtime, so avoid the slower search in metadata */
3537 mono_class_setup_methods (klass);
3538 if (klass->exception_type)
3540 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3545 * mono_get_delegate_end_invoke:
3546 * @klass: The delegate class
3548 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3551 mono_get_delegate_end_invoke (MonoClass *klass)
3555 /* This is called at runtime, so avoid the slower search in metadata */
3556 mono_class_setup_methods (klass);
3557 if (klass->exception_type)
3559 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3564 * mono_runtime_delegate_invoke:
3565 * @delegate: pointer to a delegate object.
3566 * @params: parameters for the delegate.
3567 * @exc: Pointer to the exception result.
3569 * Invokes the delegate method @delegate with the parameters provided.
3571 * You can pass NULL as the exc argument if you don't want to
3572 * catch exceptions, otherwise, *exc will be set to the exception
3573 * thrown, if any. if an exception is thrown, you can't use the
3574 * MonoObject* result from the function.
3577 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3580 MonoClass *klass = delegate->vtable->klass;
3582 im = mono_get_delegate_invoke (klass);
3584 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3586 return mono_runtime_invoke (im, delegate, params, exc);
3589 static char **main_args = NULL;
3590 static int num_main_args = 0;
3593 * mono_runtime_get_main_args:
3595 * Returns: a MonoArray with the arguments passed to the main program
3598 mono_runtime_get_main_args (void)
3602 MonoDomain *domain = mono_domain_get ();
3604 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3606 for (i = 0; i < num_main_args; ++i)
3607 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3613 free_main_args (void)
3617 for (i = 0; i < num_main_args; ++i)
3618 g_free (main_args [i]);
3625 * mono_runtime_set_main_args:
3626 * @argc: number of arguments from the command line
3627 * @argv: array of strings from the command line
3629 * Set the command line arguments from an embedding application that doesn't otherwise call
3630 * mono_runtime_run_main ().
3633 mono_runtime_set_main_args (int argc, char* argv[])
3638 main_args = g_new0 (char*, argc);
3639 num_main_args = argc;
3641 for (i = 0; i < argc; ++i) {
3644 utf8_arg = mono_utf8_from_external (argv[i]);
3645 if (utf8_arg == NULL) {
3646 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3647 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3651 main_args [i] = utf8_arg;
3658 * mono_runtime_run_main:
3659 * @method: the method to start the application with (usually Main)
3660 * @argc: number of arguments from the command line
3661 * @argv: array of strings from the command line
3662 * @exc: excetption results
3664 * Execute a standard Main() method (argc/argv contains the
3665 * executable name). This method also sets the command line argument value
3666 * needed by System.Environment.
3671 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3675 MonoArray *args = NULL;
3676 MonoDomain *domain = mono_domain_get ();
3677 gchar *utf8_fullpath;
3678 MonoMethodSignature *sig;
3680 g_assert (method != NULL);
3682 mono_thread_set_main (mono_thread_current ());
3684 main_args = g_new0 (char*, argc);
3685 num_main_args = argc;
3687 if (!g_path_is_absolute (argv [0])) {
3688 gchar *basename = g_path_get_basename (argv [0]);
3689 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3693 utf8_fullpath = mono_utf8_from_external (fullpath);
3694 if(utf8_fullpath == NULL) {
3695 /* Printing the arg text will cause glib to
3696 * whinge about "Invalid UTF-8", but at least
3697 * its relevant, and shows the problem text
3700 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3701 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3708 utf8_fullpath = mono_utf8_from_external (argv[0]);
3709 if(utf8_fullpath == NULL) {
3710 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3711 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3716 main_args [0] = utf8_fullpath;
3718 for (i = 1; i < argc; ++i) {
3721 utf8_arg=mono_utf8_from_external (argv[i]);
3722 if(utf8_arg==NULL) {
3723 /* Ditto the comment about Invalid UTF-8 here */
3724 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3725 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3729 main_args [i] = utf8_arg;
3734 sig = mono_method_signature (method);
3736 g_print ("Unable to load Main method.\n");
3740 if (sig->param_count) {
3741 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3742 for (i = 0; i < argc; ++i) {
3743 /* The encodings should all work, given that
3744 * we've checked all these args for the
3747 gchar *str = mono_utf8_from_external (argv [i]);
3748 MonoString *arg = mono_string_new (domain, str);
3749 mono_array_setref (args, i, arg);
3753 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3756 mono_assembly_set_main (method->klass->image->assembly);
3758 return mono_runtime_exec_main (method, args, exc);
3762 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3764 static MonoMethod *serialize_method;
3769 if (!serialize_method) {
3770 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3771 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3774 if (!serialize_method) {
3779 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3783 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3791 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3793 static MonoMethod *deserialize_method;
3798 if (!deserialize_method) {
3799 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3800 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3802 if (!deserialize_method) {
3809 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3816 #ifndef DISABLE_REMOTING
3818 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3820 static MonoMethod *get_proxy_method;
3822 MonoDomain *domain = mono_domain_get ();
3823 MonoRealProxy *real_proxy;
3824 MonoReflectionType *reflection_type;
3825 MonoTransparentProxy *transparent_proxy;
3827 if (!get_proxy_method)
3828 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3830 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3832 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3833 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3835 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3836 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3839 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3843 return (MonoObject*) transparent_proxy;
3845 #endif /* DISABLE_REMOTING */
3848 * mono_object_xdomain_representation
3850 * @target_domain: a domain
3851 * @exc: pointer to a MonoObject*
3853 * Creates a representation of obj in the domain target_domain. This
3854 * is either a copy of obj arrived through via serialization and
3855 * deserialization or a proxy, depending on whether the object is
3856 * serializable or marshal by ref. obj must not be in target_domain.
3858 * If the object cannot be represented in target_domain, NULL is
3859 * returned and *exc is set to an appropriate exception.
3862 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3864 MonoObject *deserialized = NULL;
3865 gboolean failure = FALSE;
3869 #ifndef DISABLE_REMOTING
3870 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3871 deserialized = make_transparent_proxy (obj, &failure, exc);
3876 MonoDomain *domain = mono_domain_get ();
3877 MonoObject *serialized;
3879 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3880 serialized = serialize_object (obj, &failure, exc);
3881 mono_domain_set_internal_with_options (target_domain, FALSE);
3883 deserialized = deserialize_object (serialized, &failure, exc);
3884 if (domain != target_domain)
3885 mono_domain_set_internal_with_options (domain, FALSE);
3888 return deserialized;
3891 /* Used in call_unhandled_exception_delegate */
3893 create_unhandled_exception_eventargs (MonoObject *exc)
3897 MonoMethod *method = NULL;
3898 MonoBoolean is_terminating = TRUE;
3901 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3904 mono_class_init (klass);
3906 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3907 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3911 args [1] = &is_terminating;
3913 obj = mono_object_new (mono_domain_get (), klass);
3914 mono_runtime_invoke (method, obj, args, NULL);
3919 /* Used in mono_unhandled_exception */
3921 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3922 MonoObject *e = NULL;
3924 MonoDomain *current_domain = mono_domain_get ();
3926 if (domain != current_domain)
3927 mono_domain_set_internal_with_options (domain, FALSE);
3929 g_assert (domain == mono_object_domain (domain->domain));
3931 if (mono_object_domain (exc) != domain) {
3932 MonoObject *serialization_exc;
3934 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3936 if (serialization_exc) {
3938 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3941 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3942 "System.Runtime.Serialization", "SerializationException",
3943 "Could not serialize unhandled exception.");
3947 g_assert (mono_object_domain (exc) == domain);
3949 pa [0] = domain->domain;
3950 pa [1] = create_unhandled_exception_eventargs (exc);
3951 mono_runtime_delegate_invoke (delegate, pa, &e);
3953 if (domain != current_domain)
3954 mono_domain_set_internal_with_options (current_domain, FALSE);
3958 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3959 if (!mono_error_ok (&error)) {
3960 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3961 mono_error_cleanup (&error);
3963 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3969 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3972 * mono_runtime_unhandled_exception_policy_set:
3973 * @policy: the new policy
3975 * This is a VM internal routine.
3977 * Sets the runtime policy for handling unhandled exceptions.
3980 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3981 runtime_unhandled_exception_policy = policy;
3985 * mono_runtime_unhandled_exception_policy_get:
3987 * This is a VM internal routine.
3989 * Gets the runtime policy for handling unhandled exceptions.
3991 MonoRuntimeUnhandledExceptionPolicy
3992 mono_runtime_unhandled_exception_policy_get (void) {
3993 return runtime_unhandled_exception_policy;
3997 * mono_unhandled_exception:
3998 * @exc: exception thrown
4000 * This is a VM internal routine.
4002 * We call this function when we detect an unhandled exception
4003 * in the default domain.
4005 * It invokes the * UnhandledException event in AppDomain or prints
4006 * a warning to the console
4009 mono_unhandled_exception (MonoObject *exc)
4011 MonoDomain *current_domain = mono_domain_get ();
4012 MonoDomain *root_domain = mono_get_root_domain ();
4013 MonoClassField *field;
4014 MonoObject *current_appdomain_delegate;
4015 MonoObject *root_appdomain_delegate;
4017 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
4018 "UnhandledException");
4021 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4022 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4023 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4024 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4025 if (current_domain != root_domain) {
4026 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4028 current_appdomain_delegate = NULL;
4031 /* set exitcode only if we will abort the process */
4032 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4034 mono_environment_exitcode_set (1);
4035 mono_print_unhandled_exception (exc);
4037 if (root_appdomain_delegate) {
4038 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4040 if (current_appdomain_delegate) {
4041 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4048 * mono_runtime_exec_managed_code:
4049 * @domain: Application domain
4050 * @main_func: function to invoke from the execution thread
4051 * @main_args: parameter to the main_func
4053 * Launch a new thread to execute a function
4055 * main_func is called back from the thread with main_args as the
4056 * parameter. The callback function is expected to start Main()
4057 * eventually. This function then waits for all managed threads to
4059 * It is not necesseray anymore to execute managed code in a subthread,
4060 * so this function should not be used anymore by default: just
4061 * execute the code and then call mono_thread_manage ().
4064 mono_runtime_exec_managed_code (MonoDomain *domain,
4065 MonoMainThreadFunc main_func,
4068 mono_thread_create (domain, main_func, main_args);
4070 mono_thread_manage ();
4074 * Execute a standard Main() method (args doesn't contain the
4078 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4083 MonoCustomAttrInfo* cinfo;
4084 gboolean has_stathread_attribute;
4085 MonoInternalThread* thread = mono_thread_internal_current ();
4091 domain = mono_object_domain (args);
4092 if (!domain->entry_assembly) {
4094 MonoAssembly *assembly;
4096 assembly = method->klass->image->assembly;
4097 domain->entry_assembly = assembly;
4098 /* Domains created from another domain already have application_base and configuration_file set */
4099 if (domain->setup->application_base == NULL) {
4100 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4103 if (domain->setup->configuration_file == NULL) {
4104 str = g_strconcat (assembly->image->name, ".config", NULL);
4105 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4107 mono_set_private_bin_path_from_config (domain);
4111 cinfo = mono_custom_attrs_from_method (method);
4113 static MonoClass *stathread_attribute = NULL;
4114 if (!stathread_attribute)
4115 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4116 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4118 mono_custom_attrs_free (cinfo);
4120 has_stathread_attribute = FALSE;
4122 if (has_stathread_attribute) {
4123 thread->apartment_state = ThreadApartmentState_STA;
4125 thread->apartment_state = ThreadApartmentState_MTA;
4127 mono_thread_init_apartment_state ();
4129 /* FIXME: check signature of method */
4130 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4132 res = mono_runtime_invoke (method, NULL, pa, exc);
4134 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4138 mono_environment_exitcode_set (rval);
4140 mono_runtime_invoke (method, NULL, pa, exc);
4144 /* If the return type of Main is void, only
4145 * set the exitcode if an exception was thrown
4146 * (we don't want to blow away an
4147 * explicitly-set exit code)
4150 mono_environment_exitcode_set (rval);
4158 * mono_install_runtime_invoke:
4159 * @func: Function to install
4161 * This is a VM internal routine
4164 mono_install_runtime_invoke (MonoInvokeFunc func)
4166 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4171 * mono_runtime_invoke_array:
4172 * @method: method to invoke
4173 * @obJ: object instance
4174 * @params: arguments to the method
4175 * @exc: exception information.
4177 * Invokes the method represented by @method on the object @obj.
4179 * obj is the 'this' pointer, it should be NULL for static
4180 * methods, a MonoObject* for object instances and a pointer to
4181 * the value type for value types.
4183 * The params array contains the arguments to the method with the
4184 * same convention: MonoObject* pointers for object instances and
4185 * pointers to the value type otherwise. The _invoke_array
4186 * variant takes a C# object[] as the params argument (MonoArray
4187 * *params): in this case the value types are boxed inside the
4188 * respective reference representation.
4190 * From unmanaged code you'll usually use the
4191 * mono_runtime_invoke() variant.
4193 * Note that this function doesn't handle virtual methods for
4194 * you, it will exec the exact method you pass: we still need to
4195 * expose a function to lookup the derived class implementation
4196 * of a virtual method (there are examples of this in the code,
4199 * You can pass NULL as the exc argument if you don't want to
4200 * catch exceptions, otherwise, *exc will be set to the exception
4201 * thrown, if any. if an exception is thrown, you can't use the
4202 * MonoObject* result from the function.
4204 * If the method returns a value type, it is boxed in an object
4208 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4211 MonoMethodSignature *sig = mono_method_signature (method);
4212 gpointer *pa = NULL;
4215 gboolean has_byref_nullables = FALSE;
4217 if (NULL != params) {
4218 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4219 for (i = 0; i < mono_array_length (params); i++) {
4220 MonoType *t = sig->params [i];
4226 case MONO_TYPE_BOOLEAN:
4229 case MONO_TYPE_CHAR:
4238 case MONO_TYPE_VALUETYPE:
4239 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4240 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4241 pa [i] = mono_array_get (params, MonoObject*, i);
4243 has_byref_nullables = TRUE;
4245 /* MS seems to create the objects if a null is passed in */
4246 if (!mono_array_get (params, MonoObject*, i))
4247 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4251 * We can't pass the unboxed vtype byref to the callee, since
4252 * that would mean the callee would be able to modify boxed
4253 * primitive types. So we (and MS) make a copy of the boxed
4254 * object, pass that to the callee, and replace the original
4255 * boxed object in the arg array with the copy.
4257 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4258 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4259 mono_array_setref (params, i, copy);
4262 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4265 case MONO_TYPE_STRING:
4266 case MONO_TYPE_OBJECT:
4267 case MONO_TYPE_CLASS:
4268 case MONO_TYPE_ARRAY:
4269 case MONO_TYPE_SZARRAY:
4271 pa [i] = mono_array_addr (params, MonoObject*, i);
4272 // FIXME: I need to check this code path
4274 pa [i] = mono_array_get (params, MonoObject*, i);
4276 case MONO_TYPE_GENERICINST:
4278 t = &t->data.generic_class->container_class->this_arg;
4280 t = &t->data.generic_class->container_class->byval_arg;
4282 case MONO_TYPE_PTR: {
4285 /* The argument should be an IntPtr */
4286 arg = mono_array_get (params, MonoObject*, i);
4290 g_assert (arg->vtable->klass == mono_defaults.int_class);
4291 pa [i] = ((MonoIntPtr*)arg)->m_value;
4296 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4301 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4304 if (mono_class_is_nullable (method->klass)) {
4305 /* Need to create a boxed vtype instead */
4311 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4315 obj = mono_object_new (mono_domain_get (), method->klass);
4316 g_assert (obj); /*maybe we should raise a TLE instead?*/
4317 #ifndef DISABLE_REMOTING
4318 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4319 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4322 if (method->klass->valuetype)
4323 o = mono_object_unbox (obj);
4326 } else if (method->klass->valuetype) {
4327 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4330 mono_runtime_invoke (method, o, pa, exc);
4333 if (mono_class_is_nullable (method->klass)) {
4334 MonoObject *nullable;
4336 /* Convert the unboxed vtype into a Nullable structure */
4337 nullable = mono_object_new (mono_domain_get (), method->klass);
4339 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4340 obj = mono_object_unbox (nullable);
4343 /* obj must be already unboxed if needed */
4344 res = mono_runtime_invoke (method, obj, pa, exc);
4346 if (sig->ret->type == MONO_TYPE_PTR) {
4347 MonoClass *pointer_class;
4348 static MonoMethod *box_method;
4350 MonoObject *box_exc;
4353 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4354 * convert it to a Pointer object.
4356 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4358 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4360 g_assert (res->vtable->klass == mono_defaults.int_class);
4361 box_args [0] = ((MonoIntPtr*)res)->m_value;
4362 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4363 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4364 g_assert (!box_exc);
4367 if (has_byref_nullables) {
4369 * The runtime invoke wrapper already converted byref nullables back,
4370 * and stored them in pa, we just need to copy them back to the
4373 for (i = 0; i < mono_array_length (params); i++) {
4374 MonoType *t = sig->params [i];
4376 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4377 mono_array_setref (params, i, pa [i]);
4386 arith_overflow (void)
4388 mono_raise_exception (mono_get_exception_overflow ());
4392 * mono_object_allocate:
4393 * @size: number of bytes to allocate
4395 * This is a very simplistic routine until we have our GC-aware
4398 * Returns: an allocated object of size @size, or NULL on failure.
4400 static inline void *
4401 mono_object_allocate (size_t size, MonoVTable *vtable)
4404 ALLOC_OBJECT (o, vtable, size);
4409 #ifndef HAVE_SGEN_GC
4411 * mono_object_allocate_ptrfree:
4412 * @size: number of bytes to allocate
4414 * Note that the memory allocated is not zeroed.
4415 * Returns: an allocated object of size @size, or NULL on failure.
4417 static inline void *
4418 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4421 ALLOC_PTRFREE (o, vtable, size);
4426 static inline void *
4427 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4430 ALLOC_TYPED (o, size, vtable);
4437 * @klass: the class of the object that we want to create
4439 * Returns: a newly created object whose definition is
4440 * looked up using @klass. This will not invoke any constructors,
4441 * so the consumer of this routine has to invoke any constructors on
4442 * its own to initialize the object.
4444 * It returns NULL on failure.
4447 mono_object_new (MonoDomain *domain, MonoClass *klass)
4451 vtable = mono_class_vtable (domain, klass);
4454 return mono_object_new_specific (vtable);
4458 * mono_object_new_pinned:
4460 * Same as mono_object_new, but the returned object will be pinned.
4461 * For SGEN, these objects will only be freed at appdomain unload.
4464 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4468 vtable = mono_class_vtable (domain, klass);
4473 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4475 return mono_object_new_specific (vtable);
4480 * mono_object_new_specific:
4481 * @vtable: the vtable of the object that we want to create
4483 * Returns: A newly created object with class and domain specified
4487 mono_object_new_specific (MonoVTable *vtable)
4491 /* check for is_com_object for COM Interop */
4492 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4495 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4498 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4501 mono_class_init (klass);
4503 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4505 vtable->domain->create_proxy_for_type_method = im;
4508 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4510 o = mono_runtime_invoke (im, NULL, pa, NULL);
4511 if (o != NULL) return o;
4514 return mono_object_new_alloc_specific (vtable);
4518 mono_object_new_alloc_specific (MonoVTable *vtable)
4522 if (!vtable->klass->has_references) {
4523 o = mono_object_new_ptrfree (vtable);
4524 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4525 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4527 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4528 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4530 if (G_UNLIKELY (vtable->klass->has_finalize))
4531 mono_object_register_finalizer (o);
4533 if (G_UNLIKELY (profile_allocs))
4534 mono_profiler_allocation (o, vtable->klass);
4539 mono_object_new_fast (MonoVTable *vtable)
4542 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4547 mono_object_new_ptrfree (MonoVTable *vtable)
4550 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4551 #if NEED_TO_ZERO_PTRFREE
4552 /* an inline memset is much faster for the common vcase of small objects
4553 * note we assume the allocated size is a multiple of sizeof (void*).
4555 if (vtable->klass->instance_size < 128) {
4557 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4558 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4564 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4571 mono_object_new_ptrfree_box (MonoVTable *vtable)
4574 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4575 /* the object will be boxed right away, no need to memzero it */
4580 * mono_class_get_allocation_ftn:
4582 * @for_box: the object will be used for boxing
4583 * @pass_size_in_words:
4585 * Return the allocation function appropriate for the given class.
4589 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4591 *pass_size_in_words = FALSE;
4593 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4594 profile_allocs = FALSE;
4596 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4597 return mono_object_new_specific;
4599 if (!vtable->klass->has_references) {
4600 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4602 return mono_object_new_ptrfree_box;
4603 return mono_object_new_ptrfree;
4606 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4608 return mono_object_new_fast;
4611 * FIXME: This is actually slower than mono_object_new_fast, because
4612 * of the overhead of parameter passing.
4615 *pass_size_in_words = TRUE;
4616 #ifdef GC_REDIRECT_TO_LOCAL
4617 return GC_local_gcj_fast_malloc;
4619 return GC_gcj_fast_malloc;
4624 return mono_object_new_specific;
4628 * mono_object_new_from_token:
4629 * @image: Context where the type_token is hosted
4630 * @token: a token of the type that we want to create
4632 * Returns: A newly created object whose definition is
4633 * looked up using @token in the @image image
4636 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4641 class = mono_class_get_checked (image, token, &error);
4642 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4644 return mono_object_new (domain, class);
4649 * mono_object_clone:
4650 * @obj: the object to clone
4652 * Returns: A newly created object who is a shallow copy of @obj
4655 mono_object_clone (MonoObject *obj)
4658 int size = obj->vtable->klass->instance_size;
4660 if (obj->vtable->klass->rank)
4661 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4663 o = mono_object_allocate (size, obj->vtable);
4665 if (obj->vtable->klass->has_references) {
4666 mono_gc_wbarrier_object_copy (o, obj);
4668 int size = obj->vtable->klass->instance_size;
4669 /* do not copy the sync state */
4670 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4672 if (G_UNLIKELY (profile_allocs))
4673 mono_profiler_allocation (o, obj->vtable->klass);
4675 if (obj->vtable->klass->has_finalize)
4676 mono_object_register_finalizer (o);
4681 * mono_array_full_copy:
4682 * @src: source array to copy
4683 * @dest: destination array
4685 * Copies the content of one array to another with exactly the same type and size.
4688 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4691 MonoClass *klass = src->obj.vtable->klass;
4693 g_assert (klass == dest->obj.vtable->klass);
4695 size = mono_array_length (src);
4696 g_assert (size == mono_array_length (dest));
4697 size *= mono_array_element_size (klass);
4699 if (klass->element_class->valuetype) {
4700 if (klass->element_class->has_references)
4701 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4703 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4705 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4708 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4713 * mono_array_clone_in_domain:
4714 * @domain: the domain in which the array will be cloned into
4715 * @array: the array to clone
4717 * This routine returns a copy of the array that is hosted on the
4718 * specified MonoDomain.
4721 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4726 MonoClass *klass = array->obj.vtable->klass;
4728 if (array->bounds == NULL) {
4729 size = mono_array_length (array);
4730 o = mono_array_new_full (domain, klass, &size, NULL);
4732 size *= mono_array_element_size (klass);
4734 if (klass->element_class->valuetype) {
4735 if (klass->element_class->has_references)
4736 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4738 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4740 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4743 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4748 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4749 size = mono_array_element_size (klass);
4750 for (i = 0; i < klass->rank; ++i) {
4751 sizes [i] = array->bounds [i].length;
4752 size *= array->bounds [i].length;
4753 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4755 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4757 if (klass->element_class->valuetype) {
4758 if (klass->element_class->has_references)
4759 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4761 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4763 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4766 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4774 * @array: the array to clone
4776 * Returns: A newly created array who is a shallow copy of @array
4779 mono_array_clone (MonoArray *array)
4781 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4784 /* helper macros to check for overflow when calculating the size of arrays */
4785 #ifdef MONO_BIG_ARRAYS
4786 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4787 #define MYGUINT_MAX MYGUINT64_MAX
4788 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4789 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4790 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4791 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4792 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4794 #define MYGUINT32_MAX 4294967295U
4795 #define MYGUINT_MAX MYGUINT32_MAX
4796 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4797 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4798 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4799 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4800 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4804 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4808 byte_len = mono_array_element_size (class);
4809 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4812 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4814 byte_len += sizeof (MonoArray);
4822 * mono_array_new_full:
4823 * @domain: domain where the object is created
4824 * @array_class: array class
4825 * @lengths: lengths for each dimension in the array
4826 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4828 * This routine creates a new array objects with the given dimensions,
4829 * lower bounds and type.
4832 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4834 uintptr_t byte_len = 0, len, bounds_size;
4837 MonoArrayBounds *bounds;
4841 if (!array_class->inited)
4842 mono_class_init (array_class);
4846 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4847 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4849 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4853 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4855 for (i = 0; i < array_class->rank; ++i) {
4856 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4858 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4859 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4864 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4865 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4869 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4870 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4871 byte_len = (byte_len + 3) & ~3;
4872 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4873 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4874 byte_len += bounds_size;
4877 * Following three lines almost taken from mono_object_new ():
4878 * they need to be kept in sync.
4880 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4881 #ifndef HAVE_SGEN_GC
4882 if (!array_class->has_references) {
4883 o = mono_object_allocate_ptrfree (byte_len, vtable);
4884 #if NEED_TO_ZERO_PTRFREE
4885 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4887 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4888 o = mono_object_allocate_spec (byte_len, vtable);
4890 o = mono_object_allocate (byte_len, vtable);
4893 array = (MonoArray*)o;
4894 array->max_length = len;
4897 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4898 array->bounds = bounds;
4902 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4904 o = mono_gc_alloc_vector (vtable, byte_len, len);
4905 array = (MonoArray*)o;
4907 bounds = array->bounds;
4911 for (i = 0; i < array_class->rank; ++i) {
4912 bounds [i].length = lengths [i];
4914 bounds [i].lower_bound = lower_bounds [i];
4918 if (G_UNLIKELY (profile_allocs))
4919 mono_profiler_allocation (o, array_class);
4926 * @domain: domain where the object is created
4927 * @eclass: element class
4928 * @n: number of array elements
4930 * This routine creates a new szarray with @n elements of type @eclass.
4933 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4937 ac = mono_array_class_get (eclass, 1);
4940 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4944 * mono_array_new_specific:
4945 * @vtable: a vtable in the appropriate domain for an initialized class
4946 * @n: number of array elements
4948 * This routine is a fast alternative to mono_array_new() for code which
4949 * can be sure about the domain it operates in.
4952 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4958 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4963 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4964 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4967 #ifndef HAVE_SGEN_GC
4968 if (!vtable->klass->has_references) {
4969 o = mono_object_allocate_ptrfree (byte_len, vtable);
4970 #if NEED_TO_ZERO_PTRFREE
4971 ((MonoArray*)o)->bounds = NULL;
4972 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4974 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4975 o = mono_object_allocate_spec (byte_len, vtable);
4977 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4978 o = mono_object_allocate (byte_len, vtable);
4981 ao = (MonoArray *)o;
4984 o = mono_gc_alloc_vector (vtable, byte_len, n);
4988 if (G_UNLIKELY (profile_allocs))
4989 mono_profiler_allocation (o, vtable->klass);
4995 * mono_string_new_utf16:
4996 * @text: a pointer to an utf16 string
4997 * @len: the length of the string
4999 * Returns: A newly created string object which contains @text.
5002 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5006 s = mono_string_new_size (domain, len);
5007 g_assert (s != NULL);
5009 memcpy (mono_string_chars (s), text, len * 2);
5015 * mono_string_new_utf32:
5016 * @text: a pointer to an utf32 string
5017 * @len: the length of the string
5019 * Returns: A newly created string object which contains @text.
5022 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5025 mono_unichar2 *utf16_output = NULL;
5026 gint32 utf16_len = 0;
5027 GError *error = NULL;
5028 glong items_written;
5030 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5033 g_error_free (error);
5035 while (utf16_output [utf16_len]) utf16_len++;
5037 s = mono_string_new_size (domain, utf16_len);
5038 g_assert (s != NULL);
5040 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5042 g_free (utf16_output);
5048 * mono_string_new_size:
5049 * @text: a pointer to an utf16 string
5050 * @len: the length of the string
5052 * Returns: A newly created string object of @len
5055 mono_string_new_size (MonoDomain *domain, gint32 len)
5061 /* check for overflow */
5062 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5063 mono_gc_out_of_memory (-1);
5065 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5066 g_assert (size > 0);
5068 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5071 #ifndef HAVE_SGEN_GC
5072 s = mono_object_allocate_ptrfree (size, vtable);
5076 s = mono_gc_alloc_string (vtable, size, len);
5078 #if NEED_TO_ZERO_PTRFREE
5081 if (G_UNLIKELY (profile_allocs))
5082 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5088 * mono_string_new_len:
5089 * @text: a pointer to an utf8 string
5090 * @length: number of bytes in @text to consider
5092 * Returns: A newly created string object which contains @text.
5095 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5097 GError *error = NULL;
5098 MonoString *o = NULL;
5100 glong items_written;
5102 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5105 o = mono_string_new_utf16 (domain, ut, items_written);
5107 g_error_free (error);
5116 * @text: a pointer to an utf8 string
5118 * Returns: A newly created string object which contains @text.
5121 mono_string_new (MonoDomain *domain, const char *text)
5123 GError *error = NULL;
5124 MonoString *o = NULL;
5126 glong items_written;
5131 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5134 o = mono_string_new_utf16 (domain, ut, items_written);
5136 g_error_free (error);
5139 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5144 MonoString *o = NULL;
5146 if (!g_utf8_validate (text, -1, &end))
5149 len = g_utf8_strlen (text, -1);
5150 o = mono_string_new_size (domain, len);
5151 str = mono_string_chars (o);
5153 while (text < end) {
5154 *str++ = g_utf8_get_char (text);
5155 text = g_utf8_next_char (text);
5162 * mono_string_new_wrapper:
5163 * @text: pointer to utf8 characters.
5165 * Helper function to create a string object from @text in the current domain.
5168 mono_string_new_wrapper (const char *text)
5170 MonoDomain *domain = mono_domain_get ();
5173 return mono_string_new (domain, text);
5180 * @class: the class of the value
5181 * @value: a pointer to the unboxed data
5183 * Returns: A newly created object which contains @value.
5186 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5192 g_assert (class->valuetype);
5193 if (mono_class_is_nullable (class))
5194 return mono_nullable_box (value, class);
5196 vtable = mono_class_vtable (domain, class);
5199 size = mono_class_instance_size (class);
5200 res = mono_object_new_alloc_specific (vtable);
5201 if (G_UNLIKELY (profile_allocs))
5202 mono_profiler_allocation (res, class);
5204 size = size - sizeof (MonoObject);
5207 g_assert (size == mono_class_value_size (class, NULL));
5208 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5210 #if NO_UNALIGNED_ACCESS
5211 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5215 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5218 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5221 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5224 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5227 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5231 if (class->has_finalize)
5232 mono_object_register_finalizer (res);
5238 * @dest: destination pointer
5239 * @src: source pointer
5240 * @klass: a valuetype class
5242 * Copy a valuetype from @src to @dest. This function must be used
5243 * when @klass contains references fields.
5246 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5248 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5252 * mono_value_copy_array:
5253 * @dest: destination array
5254 * @dest_idx: index in the @dest array
5255 * @src: source pointer
5256 * @count: number of items
5258 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5259 * This function must be used when @klass contains references fields.
5260 * Overlap is handled.
5263 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5265 int size = mono_array_element_size (dest->obj.vtable->klass);
5266 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5267 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5268 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5272 * mono_object_get_domain:
5273 * @obj: object to query
5275 * Returns: the MonoDomain where the object is hosted
5278 mono_object_get_domain (MonoObject *obj)
5280 return mono_object_domain (obj);
5284 * mono_object_get_class:
5285 * @obj: object to query
5287 * Returns: the MonOClass of the object.
5290 mono_object_get_class (MonoObject *obj)
5292 return mono_object_class (obj);
5295 * mono_object_get_size:
5296 * @o: object to query
5298 * Returns: the size, in bytes, of @o
5301 mono_object_get_size (MonoObject* o)
5303 MonoClass* klass = mono_object_class (o);
5304 if (klass == mono_defaults.string_class) {
5305 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5306 } else if (o->vtable->rank) {
5307 MonoArray *array = (MonoArray*)o;
5308 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5309 if (array->bounds) {
5312 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5316 return mono_class_instance_size (klass);
5321 * mono_object_unbox:
5322 * @obj: object to unbox
5324 * Returns: a pointer to the start of the valuetype boxed in this
5327 * This method will assert if the object passed is not a valuetype.
5330 mono_object_unbox (MonoObject *obj)
5332 /* add assert for valuetypes? */
5333 g_assert (obj->vtable->klass->valuetype);
5334 return ((char*)obj) + sizeof (MonoObject);
5338 * mono_object_isinst:
5340 * @klass: a pointer to a class
5342 * Returns: @obj if @obj is derived from @klass
5345 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5348 mono_class_init (klass);
5350 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5351 return mono_object_isinst_mbyref (obj, klass);
5356 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5360 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5369 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5370 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5374 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5375 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5378 MonoClass *oklass = vt->klass;
5379 if (mono_class_is_transparent_proxy (oklass))
5380 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5382 mono_class_setup_supertypes (klass);
5383 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5386 #ifndef DISABLE_REMOTING
5387 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5389 MonoDomain *domain = mono_domain_get ();
5391 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5392 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5393 MonoMethod *im = NULL;
5396 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5397 im = mono_object_get_virtual_method (rp, im);
5400 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5403 res = mono_runtime_invoke (im, rp, pa, NULL);
5405 if (*(MonoBoolean *) mono_object_unbox(res)) {
5406 /* Update the vtable of the remote type, so it can safely cast to this new type */
5407 mono_upgrade_remote_class (domain, obj, klass);
5411 #endif /* DISABLE_REMOTING */
5416 * mono_object_castclass_mbyref:
5418 * @klass: a pointer to a class
5420 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5423 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5425 if (!obj) return NULL;
5426 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5428 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5430 "InvalidCastException"));
5435 MonoDomain *orig_domain;
5441 str_lookup (MonoDomain *domain, gpointer user_data)
5443 LDStrInfo *info = user_data;
5444 if (info->res || domain == info->orig_domain)
5446 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5452 mono_string_get_pinned (MonoString *str)
5456 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5457 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5459 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5460 news->length = mono_string_length (str);
5466 #define mono_string_get_pinned(str) (str)
5470 mono_string_is_interned_lookup (MonoString *str, int insert)
5472 MonoGHashTable *ldstr_table;
5473 MonoString *s, *res;
5476 domain = ((MonoObject *)str)->vtable->domain;
5477 ldstr_table = domain->ldstr_table;
5479 res = mono_g_hash_table_lookup (ldstr_table, str);
5485 /* Allocate outside the lock */
5487 s = mono_string_get_pinned (str);
5490 res = mono_g_hash_table_lookup (ldstr_table, str);
5495 mono_g_hash_table_insert (ldstr_table, s, s);
5500 LDStrInfo ldstr_info;
5501 ldstr_info.orig_domain = domain;
5502 ldstr_info.ins = str;
5503 ldstr_info.res = NULL;
5505 mono_domain_foreach (str_lookup, &ldstr_info);
5506 if (ldstr_info.res) {
5508 * the string was already interned in some other domain:
5509 * intern it in the current one as well.
5511 mono_g_hash_table_insert (ldstr_table, str, str);
5521 * mono_string_is_interned:
5522 * @o: String to probe
5524 * Returns whether the string has been interned.
5527 mono_string_is_interned (MonoString *o)
5529 return mono_string_is_interned_lookup (o, FALSE);
5533 * mono_string_intern:
5534 * @o: String to intern
5536 * Interns the string passed.
5537 * Returns: The interned string.
5540 mono_string_intern (MonoString *str)
5542 return mono_string_is_interned_lookup (str, TRUE);
5547 * @domain: the domain where the string will be used.
5548 * @image: a metadata context
5549 * @idx: index into the user string table.
5551 * Implementation for the ldstr opcode.
5552 * Returns: a loaded string from the @image/@idx combination.
5555 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5557 if (image->dynamic) {
5558 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5561 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5562 return NULL; /*FIXME we should probably be raising an exception here*/
5563 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5568 * mono_ldstr_metadata_sig
5569 * @domain: the domain for the string
5570 * @sig: the signature of a metadata string
5572 * Returns: a MonoString for a string stored in the metadata
5575 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5577 const char *str = sig;
5578 MonoString *o, *interned;
5581 len2 = mono_metadata_decode_blob_size (str, &str);
5584 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5585 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5588 guint16 *p2 = (guint16*)mono_string_chars (o);
5589 for (i = 0; i < len2; ++i) {
5590 *p2 = GUINT16_FROM_LE (*p2);
5596 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5599 return interned; /* o will get garbage collected */
5601 o = mono_string_get_pinned (o);
5604 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5606 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5616 * mono_string_to_utf8:
5617 * @s: a System.String
5619 * Returns the UTF8 representation for @s.
5620 * The resulting buffer needs to be freed with mono_free().
5622 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5625 mono_string_to_utf8 (MonoString *s)
5628 char *result = mono_string_to_utf8_checked (s, &error);
5630 if (!mono_error_ok (&error))
5631 mono_error_raise_exception (&error);
5636 * mono_string_to_utf8_checked:
5637 * @s: a System.String
5638 * @error: a MonoError.
5640 * Converts a MonoString to its UTF8 representation. May fail; check
5641 * @error to determine whether the conversion was successful.
5642 * The resulting buffer should be freed with mono_free().
5645 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5649 GError *gerror = NULL;
5651 mono_error_init (error);
5657 return g_strdup ("");
5659 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5661 mono_error_set_argument (error, "string", "%s", gerror->message);
5662 g_error_free (gerror);
5665 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5666 if (s->length > written) {
5667 /* allocate the total length and copy the part of the string that has been converted */
5668 char *as2 = g_malloc0 (s->length);
5669 memcpy (as2, as, written);
5678 * mono_string_to_utf8_ignore:
5681 * Converts a MonoString to its UTF8 representation. Will ignore
5682 * invalid surrogate pairs.
5683 * The resulting buffer should be freed with mono_free().
5687 mono_string_to_utf8_ignore (MonoString *s)
5696 return g_strdup ("");
5698 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5700 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5701 if (s->length > written) {
5702 /* allocate the total length and copy the part of the string that has been converted */
5703 char *as2 = g_malloc0 (s->length);
5704 memcpy (as2, as, written);
5713 * mono_string_to_utf8_image_ignore:
5714 * @s: a System.String
5716 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5719 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5721 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5725 * mono_string_to_utf8_mp_ignore:
5726 * @s: a System.String
5728 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5731 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5733 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5738 * mono_string_to_utf16:
5741 * Return an null-terminated array of the utf-16 chars
5742 * contained in @s. The result must be freed with g_free().
5743 * This is a temporary helper until our string implementation
5744 * is reworked to always include the null terminating char.
5747 mono_string_to_utf16 (MonoString *s)
5754 as = g_malloc ((s->length * 2) + 2);
5755 as [(s->length * 2)] = '\0';
5756 as [(s->length * 2) + 1] = '\0';
5759 return (gunichar2 *)(as);
5762 memcpy (as, mono_string_chars(s), s->length * 2);
5763 return (gunichar2 *)(as);
5767 * mono_string_to_utf32:
5770 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5771 * contained in @s. The result must be freed with g_free().
5774 mono_string_to_utf32 (MonoString *s)
5776 mono_unichar4 *utf32_output = NULL;
5777 GError *error = NULL;
5778 glong items_written;
5783 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5786 g_error_free (error);
5788 return utf32_output;
5792 * mono_string_from_utf16:
5793 * @data: the UTF16 string (LPWSTR) to convert
5795 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5797 * Returns: a MonoString.
5800 mono_string_from_utf16 (gunichar2 *data)
5802 MonoDomain *domain = mono_domain_get ();
5808 while (data [len]) len++;
5810 return mono_string_new_utf16 (domain, data, len);
5814 * mono_string_from_utf32:
5815 * @data: the UTF32 string (LPWSTR) to convert
5817 * Converts a UTF32 (UCS-4)to a MonoString.
5819 * Returns: a MonoString.
5822 mono_string_from_utf32 (mono_unichar4 *data)
5824 MonoString* result = NULL;
5825 mono_unichar2 *utf16_output = NULL;
5826 GError *error = NULL;
5827 glong items_written;
5833 while (data [len]) len++;
5835 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5838 g_error_free (error);
5840 result = mono_string_from_utf16 (utf16_output);
5841 g_free (utf16_output);
5846 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5853 r = mono_string_to_utf8_ignore (s);
5855 r = mono_string_to_utf8_checked (s, error);
5856 if (!mono_error_ok (error))
5863 len = strlen (r) + 1;
5865 mp_s = mono_mempool_alloc (mp, len);
5867 mp_s = mono_image_alloc (image, len);
5869 memcpy (mp_s, r, len);
5877 * mono_string_to_utf8_image:
5878 * @s: a System.String
5880 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5883 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5885 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5889 * mono_string_to_utf8_mp:
5890 * @s: a System.String
5892 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5895 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5897 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5901 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5904 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5906 eh_callbacks = *cbs;
5909 MonoRuntimeExceptionHandlingCallbacks *
5910 mono_get_eh_callbacks (void)
5912 return &eh_callbacks;
5916 * mono_raise_exception:
5917 * @ex: exception object
5919 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5922 mono_raise_exception (MonoException *ex)
5925 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5926 * that will cause gcc to omit the function epilog, causing problems when
5927 * the JIT tries to walk the stack, since the return address on the stack
5928 * will point into the next function in the executable, not this one.
5930 eh_callbacks.mono_raise_exception (ex);
5934 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5936 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5940 * mono_wait_handle_new:
5941 * @domain: Domain where the object will be created
5942 * @handle: Handle for the wait handle
5944 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5947 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5949 MonoWaitHandle *res;
5950 gpointer params [1];
5951 static MonoMethod *handle_set;
5953 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5955 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5957 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5959 params [0] = &handle;
5960 mono_runtime_invoke (handle_set, res, params, NULL);
5966 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5968 static MonoClassField *f_os_handle;
5969 static MonoClassField *f_safe_handle;
5971 if (!f_os_handle && !f_safe_handle) {
5972 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5973 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5978 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5982 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5989 mono_runtime_capture_context (MonoDomain *domain)
5991 RuntimeInvokeFunction runtime_invoke;
5993 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5994 MonoMethod *method = mono_get_context_capture_method ();
5995 MonoMethod *wrapper;
5998 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5999 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6000 domain->capture_context_method = mono_compile_method (method);
6003 runtime_invoke = domain->capture_context_runtime_invoke;
6005 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6008 * mono_async_result_new:
6009 * @domain:domain where the object will be created.
6010 * @handle: wait handle.
6011 * @state: state to pass to AsyncResult
6012 * @data: C closure data.
6014 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6015 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6019 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6021 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6022 MonoObject *context = mono_runtime_capture_context (domain);
6023 /* we must capture the execution context from the original thread */
6025 MONO_OBJECT_SETREF (res, execution_context, context);
6026 /* note: result may be null if the flow is suppressed */
6030 MONO_OBJECT_SETREF (res, object_data, object_data);
6031 MONO_OBJECT_SETREF (res, async_state, state);
6033 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6035 res->sync_completed = FALSE;
6036 res->completed = FALSE;
6042 mono_async_result_invoke (MonoAsyncResult *ares, MonoObject **exc)
6046 MonoInternalThread *thread;
6049 g_assert (ares->async_delegate);
6051 thread = mono_thread_internal_current ();
6053 if (!ares->execution_context) {
6054 ares->original_context = NULL;
6056 /* use captured ExecutionContext (if available) */
6057 MONO_OBJECT_SETREF (ares, original_context, mono_thread_get_execution_context ());
6058 mono_thread_set_execution_context (ares->execution_context);
6061 ac = (MonoAsyncCall*) ares->object_data;
6063 thread->async_invoke_method = ((MonoDelegate*) ares->async_delegate)->method;
6064 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, exc);
6065 thread->async_invoke_method = NULL;
6067 MonoArray *out_args = NULL;
6068 gpointer wait_event = NULL;
6070 ac->msg->exc = NULL;
6071 res = mono_message_invoke (ares->async_delegate, ac->msg, exc, &out_args);
6072 MONO_OBJECT_SETREF (ac->msg, exc, *exc);
6073 MONO_OBJECT_SETREF (ac, res, res);
6074 MONO_OBJECT_SETREF (ac, out_args, out_args);
6076 mono_monitor_enter ((MonoObject*) ares);
6077 ares->completed = 1;
6079 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6080 mono_monitor_exit ((MonoObject*) ares);
6082 if (wait_event != NULL)
6083 SetEvent (wait_event);
6085 if (!ac->cb_method) {
6088 thread->async_invoke_method = ac->cb_method;
6089 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, exc);
6090 thread->async_invoke_method = NULL;
6094 /* restore original thread execution context if flow isn't suppressed, i.e. non null */
6095 if (ares->original_context) {
6096 mono_thread_set_execution_context (ares->original_context);
6097 ares->original_context = NULL;
6104 mono_message_init (MonoDomain *domain,
6105 MonoMethodMessage *this,
6106 MonoReflectionMethod *method,
6107 MonoArray *out_args)
6109 static MonoClass *object_array_klass;
6110 static MonoClass *byte_array_klass;
6111 static MonoClass *string_array_klass;
6112 MonoMethodSignature *sig = mono_method_signature (method->method);
6118 if (!object_array_klass) {
6121 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6123 byte_array_klass = klass;
6125 klass = mono_array_class_get (mono_defaults.string_class, 1);
6127 string_array_klass = klass;
6129 klass = mono_array_class_get (mono_defaults.object_class, 1);
6132 mono_atomic_store_release (&object_array_klass, klass);
6135 MONO_OBJECT_SETREF (this, method, method);
6137 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6138 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6139 this->async_result = NULL;
6140 this->call_type = CallType_Sync;
6142 names = g_new (char *, sig->param_count);
6143 mono_method_get_param_names (method->method, (const char **) names);
6144 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6146 for (i = 0; i < sig->param_count; i++) {
6147 name = mono_string_new (domain, names [i]);
6148 mono_array_setref (this->names, i, name);
6152 for (i = 0, j = 0; i < sig->param_count; i++) {
6153 if (sig->params [i]->byref) {
6155 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6156 mono_array_setref (this->args, i, arg);
6160 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6164 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6167 mono_array_set (this->arg_types, guint8, i, arg_type);
6171 #ifndef DISABLE_REMOTING
6173 * mono_remoting_invoke:
6174 * @real_proxy: pointer to a RealProxy object
6175 * @msg: The MonoMethodMessage to execute
6176 * @exc: used to store exceptions
6177 * @out_args: used to store output arguments
6179 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6180 * IMessage interface and it is not trivial to extract results from there. So
6181 * we call an helper method PrivateInvoke instead of calling
6182 * RealProxy::Invoke() directly.
6184 * Returns: the result object.
6187 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6188 MonoObject **exc, MonoArray **out_args)
6190 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6193 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6196 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6198 real_proxy->vtable->domain->private_invoke_method = im;
6201 pa [0] = real_proxy;
6206 return mono_runtime_invoke (im, NULL, pa, exc);
6211 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6212 MonoObject **exc, MonoArray **out_args)
6214 static MonoClass *object_array_klass;
6217 MonoMethodSignature *sig;
6219 int i, j, outarg_count = 0;
6221 #ifndef DISABLE_REMOTING
6222 if (target && mono_object_is_transparent_proxy (target)) {
6223 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6224 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6225 target = tp->rp->unwrapped_server;
6227 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6232 domain = mono_domain_get ();
6233 method = msg->method->method;
6234 sig = mono_method_signature (method);
6236 for (i = 0; i < sig->param_count; i++) {
6237 if (sig->params [i]->byref)
6241 if (!object_array_klass) {
6244 klass = mono_array_class_get (mono_defaults.object_class, 1);
6247 mono_memory_barrier ();
6248 object_array_klass = klass;
6251 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6252 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6255 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6257 for (i = 0, j = 0; i < sig->param_count; i++) {
6258 if (sig->params [i]->byref) {
6260 arg = mono_array_get (msg->args, gpointer, i);
6261 mono_array_setref (*out_args, j, arg);
6270 * mono_object_to_string:
6272 * @exc: Any exception thrown by ToString (). May be NULL.
6274 * Returns: the result of calling ToString () on an object.
6277 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6279 static MonoMethod *to_string = NULL;
6286 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6288 method = mono_object_get_virtual_method (obj, to_string);
6290 // Unbox value type if needed
6291 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6292 target = mono_object_unbox (obj);
6295 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6299 * mono_print_unhandled_exception:
6300 * @exc: The exception
6302 * Prints the unhandled exception.
6305 mono_print_unhandled_exception (MonoObject *exc)
6308 char *message = (char*)"";
6309 gboolean free_message = FALSE;
6312 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6313 message = g_strdup ("OutOfMemoryException");
6314 free_message = TRUE;
6317 if (((MonoException*)exc)->native_trace_ips) {
6318 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6319 free_message = TRUE;
6321 MonoObject *other_exc = NULL;
6322 str = mono_object_to_string (exc, &other_exc);
6324 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6325 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6327 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6328 original_backtrace, nested_backtrace);
6330 g_free (original_backtrace);
6331 g_free (nested_backtrace);
6332 free_message = TRUE;
6334 message = mono_string_to_utf8_checked (str, &error);
6335 if (!mono_error_ok (&error)) {
6336 mono_error_cleanup (&error);
6337 message = (char *) "";
6339 free_message = TRUE;
6346 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6347 * exc->vtable->klass->name, message);
6349 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6356 * mono_delegate_ctor:
6357 * @this: pointer to an uninitialized delegate object
6358 * @target: target object
6359 * @addr: pointer to native code
6362 * Initialize a delegate and sets a specific method, not the one
6363 * associated with addr. This is useful when sharing generic code.
6364 * In that case addr will most probably not be associated with the
6365 * correct instantiation of the method.
6368 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6370 MonoDelegate *delegate = (MonoDelegate *)this;
6376 delegate->method = method;
6378 mono_stats.delegate_creations++;
6380 #ifndef DISABLE_REMOTING
6381 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6383 method = mono_marshal_get_remoting_invoke (method);
6384 delegate->method_ptr = mono_compile_method (method);
6385 MONO_OBJECT_SETREF (delegate, target, target);
6389 delegate->method_ptr = addr;
6390 MONO_OBJECT_SETREF (delegate, target, target);
6393 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6397 * mono_delegate_ctor:
6398 * @this: pointer to an uninitialized delegate object
6399 * @target: target object
6400 * @addr: pointer to native code
6402 * This is used to initialize a delegate.
6405 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6407 MonoDomain *domain = mono_domain_get ();
6409 MonoMethod *method = NULL;
6413 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6415 if (!ji && domain != mono_get_root_domain ())
6416 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6418 method = mono_jit_info_get_method (ji);
6419 g_assert (!method->klass->generic_container);
6422 mono_delegate_ctor_with_method (this, target, addr, method);
6426 * mono_method_call_message_new:
6427 * @method: method to encapsulate
6428 * @params: parameters to the method
6429 * @invoke: optional, delegate invoke.
6430 * @cb: async callback delegate.
6431 * @state: state passed to the async callback.
6433 * Translates arguments pointers into a MonoMethodMessage.
6436 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6437 MonoDelegate **cb, MonoObject **state)
6439 MonoDomain *domain = mono_domain_get ();
6440 MonoMethodSignature *sig = mono_method_signature (method);
6441 MonoMethodMessage *msg;
6444 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6447 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6448 count = sig->param_count - 2;
6450 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6451 count = sig->param_count;
6454 for (i = 0; i < count; i++) {
6459 if (sig->params [i]->byref)
6460 vpos = *((gpointer *)params [i]);
6464 class = mono_class_from_mono_type (sig->params [i]);
6466 if (class->valuetype)
6467 arg = mono_value_box (domain, class, vpos);
6469 arg = *((MonoObject **)vpos);
6471 mono_array_setref (msg->args, i, arg);
6474 if (cb != NULL && state != NULL) {
6475 *cb = *((MonoDelegate **)params [i]);
6477 *state = *((MonoObject **)params [i]);
6484 * mono_method_return_message_restore:
6486 * Restore results from message based processing back to arguments pointers
6489 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6491 MonoMethodSignature *sig = mono_method_signature (method);
6492 int i, j, type, size, out_len;
6494 if (out_args == NULL)
6496 out_len = mono_array_length (out_args);
6500 for (i = 0, j = 0; i < sig->param_count; i++) {
6501 MonoType *pt = sig->params [i];
6506 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6508 arg = mono_array_get (out_args, gpointer, j);
6511 g_assert (type != MONO_TYPE_VOID);
6513 if (MONO_TYPE_IS_REFERENCE (pt)) {
6514 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6517 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6518 size = mono_class_value_size (class, NULL);
6519 if (class->has_references)
6520 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6522 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6524 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6525 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6534 #ifndef DISABLE_REMOTING
6537 * mono_load_remote_field:
6538 * @this: pointer to an object
6539 * @klass: klass of the object containing @field
6540 * @field: the field to load
6541 * @res: a storage to store the result
6543 * This method is called by the runtime on attempts to load fields of
6544 * transparent proxy objects. @this points to such TP, @klass is the class of
6545 * the object containing @field. @res is a storage location which can be
6546 * used to store the result.
6548 * Returns: an address pointing to the value of field.
6551 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6553 static MonoMethod *getter = NULL;
6554 MonoDomain *domain = mono_domain_get ();
6555 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6556 MonoClass *field_class;
6557 MonoMethodMessage *msg;
6558 MonoArray *out_args;
6562 g_assert (mono_object_is_transparent_proxy (this));
6563 g_assert (res != NULL);
6565 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6566 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6571 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6575 field_class = mono_class_from_mono_type (field->type);
6577 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6578 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6579 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6581 full_name = mono_type_get_full_name (klass);
6582 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6583 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6586 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6588 if (exc) mono_raise_exception ((MonoException *)exc);
6590 if (mono_array_length (out_args) == 0)
6593 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6595 if (field_class->valuetype) {
6596 return ((char *)*res) + sizeof (MonoObject);
6602 * mono_load_remote_field_new:
6607 * Missing documentation.
6610 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6612 static MonoMethod *getter = NULL;
6613 MonoDomain *domain = mono_domain_get ();
6614 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6615 MonoClass *field_class;
6616 MonoMethodMessage *msg;
6617 MonoArray *out_args;
6618 MonoObject *exc, *res;
6621 g_assert (mono_object_is_transparent_proxy (this));
6623 field_class = mono_class_from_mono_type (field->type);
6625 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6627 if (field_class->valuetype) {
6628 res = mono_object_new (domain, field_class);
6629 val = ((gchar *) res) + sizeof (MonoObject);
6633 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6638 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6642 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6643 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6645 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6647 full_name = mono_type_get_full_name (klass);
6648 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6649 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6652 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6654 if (exc) mono_raise_exception ((MonoException *)exc);
6656 if (mono_array_length (out_args) == 0)
6659 res = mono_array_get (out_args, MonoObject *, 0);
6665 * mono_store_remote_field:
6666 * @this: pointer to an object
6667 * @klass: klass of the object containing @field
6668 * @field: the field to load
6669 * @val: the value/object to store
6671 * This method is called by the runtime on attempts to store fields of
6672 * transparent proxy objects. @this points to such TP, @klass is the class of
6673 * the object containing @field. @val is the new value to store in @field.
6676 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6678 static MonoMethod *setter = NULL;
6679 MonoDomain *domain = mono_domain_get ();
6680 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6681 MonoClass *field_class;
6682 MonoMethodMessage *msg;
6683 MonoArray *out_args;
6688 g_assert (mono_object_is_transparent_proxy (this));
6690 field_class = mono_class_from_mono_type (field->type);
6692 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6693 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6694 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6699 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6703 if (field_class->valuetype)
6704 arg = mono_value_box (domain, field_class, val);
6706 arg = *((MonoObject **)val);
6709 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6710 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6712 full_name = mono_type_get_full_name (klass);
6713 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6714 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6715 mono_array_setref (msg->args, 2, arg);
6718 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6720 if (exc) mono_raise_exception ((MonoException *)exc);
6724 * mono_store_remote_field_new:
6730 * Missing documentation
6733 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6735 static MonoMethod *setter = NULL;
6736 MonoDomain *domain = mono_domain_get ();
6737 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6738 MonoClass *field_class;
6739 MonoMethodMessage *msg;
6740 MonoArray *out_args;
6744 g_assert (mono_object_is_transparent_proxy (this));
6746 field_class = mono_class_from_mono_type (field->type);
6748 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6749 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6750 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6755 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6759 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6760 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6762 full_name = mono_type_get_full_name (klass);
6763 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6764 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6765 mono_array_setref (msg->args, 2, arg);
6768 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6770 if (exc) mono_raise_exception ((MonoException *)exc);
6775 * mono_create_ftnptr:
6777 * Given a function address, create a function descriptor for it.
6778 * This is only needed on some platforms.
6781 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6783 return callbacks.create_ftnptr (domain, addr);
6787 * mono_get_addr_from_ftnptr:
6789 * Given a pointer to a function descriptor, return the function address.
6790 * This is only needed on some platforms.
6793 mono_get_addr_from_ftnptr (gpointer descr)
6795 return callbacks.get_addr_from_ftnptr (descr);
6799 * mono_string_chars:
6802 * Returns a pointer to the UCS16 characters stored in the MonoString
6805 mono_string_chars (MonoString *s)
6811 * mono_string_length:
6814 * Returns the lenght in characters of the string
6817 mono_string_length (MonoString *s)
6823 * mono_array_length:
6824 * @array: a MonoArray*
6826 * Returns the total number of elements in the array. This works for
6827 * both vectors and multidimensional arrays.
6830 mono_array_length (MonoArray *array)
6832 return array->max_length;
6836 * mono_array_addr_with_size:
6837 * @array: a MonoArray*
6838 * @size: size of the array elements
6839 * @idx: index into the array
6841 * Returns the address of the @idx element in the array.
6844 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6846 return ((char*)(array)->vector) + size * idx;