2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include "cominterop.h"
49 #define NEED_TO_ZERO_PTRFREE 1
50 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
51 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
52 #ifdef HAVE_GC_GCJ_MALLOC
53 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
61 #define GC_NO_DESCRIPTOR (NULL)
62 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
66 #define NEED_TO_ZERO_PTRFREE 1
67 #define GC_NO_DESCRIPTOR (NULL)
68 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
69 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
70 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
84 free_main_args (void);
87 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
90 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
91 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
92 static mono_mutex_t ldstr_section;
94 static gboolean profile_allocs = TRUE;
97 mono_runtime_object_init (MonoObject *this)
99 MonoMethod *method = NULL;
100 MonoClass *klass = this->vtable->klass;
102 method = mono_class_get_method_from_name (klass, ".ctor", 0);
104 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
106 if (method->klass->valuetype)
107 this = mono_object_unbox (this);
108 mono_runtime_invoke (method, this, NULL, NULL);
111 /* The pseudo algorithm for type initialization from the spec
112 Note it doesn't say anything about domains - only threads.
114 2. If the type is initialized you are done.
115 2.1. If the type is not yet initialized, try to take an
117 2.2. If successful, record this thread as responsible for
118 initializing the type and proceed to step 2.3.
119 2.2.1. If not, see whether this thread or any thread
120 waiting for this thread to complete already holds the lock.
121 2.2.2. If so, return since blocking would create a deadlock. This thread
122 will now see an incompletely initialized state for the type,
123 but no deadlock will arise.
124 2.2.3 If not, block until the type is initialized then return.
125 2.3 Initialize the parent type and then all interfaces implemented
127 2.4 Execute the type initialization code for this type.
128 2.5 Mark the type as initialized, release the initialization lock,
129 awaken any threads waiting for this type to be initialized,
136 guint32 initializing_tid;
137 guint32 waiting_count;
139 mono_mutex_t initialization_section;
140 } TypeInitializationLock;
142 /* for locking access to type_initialization_hash and blocked_thread_hash */
143 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
144 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
145 static mono_mutex_t type_initialization_section;
147 /* from vtable to lock */
148 static GHashTable *type_initialization_hash;
150 /* from thread id to thread id being waited on */
151 static GHashTable *blocked_thread_hash;
154 static MonoThread *main_thread;
156 /* Functions supplied by the runtime */
157 static MonoRuntimeCallbacks callbacks;
160 * mono_thread_set_main:
161 * @thread: thread to set as the main thread
163 * This function can be used to instruct the runtime to treat @thread
164 * as the main thread, ie, the thread that would normally execute the Main()
165 * method. This basically means that at the end of @thread, the runtime will
166 * wait for the existing foreground threads to quit and other such details.
169 mono_thread_set_main (MonoThread *thread)
171 static gboolean registered = FALSE;
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
178 main_thread = thread;
182 mono_thread_get_main (void)
188 mono_type_initialization_init (void)
190 mono_mutex_init_recursive (&type_initialization_section);
191 type_initialization_hash = g_hash_table_new (NULL, NULL);
192 blocked_thread_hash = g_hash_table_new (NULL, NULL);
193 mono_mutex_init_recursive (&ldstr_section);
197 mono_type_initialization_cleanup (void)
200 /* This is causing race conditions with
201 * mono_release_type_locks
203 mono_mutex_destroy (&type_initialization_section);
204 g_hash_table_destroy (type_initialization_hash);
205 type_initialization_hash = NULL;
207 mono_mutex_destroy (&ldstr_section);
208 g_hash_table_destroy (blocked_thread_hash);
209 blocked_thread_hash = NULL;
215 * get_type_init_exception_for_vtable:
217 * Return the stored type initialization exception for VTABLE.
219 static MonoException*
220 get_type_init_exception_for_vtable (MonoVTable *vtable)
222 MonoDomain *domain = vtable->domain;
223 MonoClass *klass = vtable->klass;
227 if (!vtable->init_failed)
228 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
231 * If the initializing thread was rudely aborted, the exception is not stored
235 mono_domain_lock (domain);
236 if (domain->type_init_exception_hash)
237 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
238 mono_domain_unlock (domain);
241 if (klass->name_space && *klass->name_space)
242 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
244 full_name = g_strdup (klass->name);
245 ex = mono_get_exception_type_initialization (full_name, NULL);
252 * mono_runtime_class_init:
253 * @vtable: vtable that needs to be initialized
255 * This routine calls the class constructor for @vtable.
258 mono_runtime_class_init (MonoVTable *vtable)
260 mono_runtime_class_init_full (vtable, TRUE);
264 * mono_runtime_class_init_full:
265 * @vtable that neeeds to be initialized
266 * @raise_exception is TRUE, exceptions are raised intead of returned
270 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
273 MonoException *exc_to_throw;
274 MonoMethod *method = NULL;
278 if (vtable->initialized)
282 klass = vtable->klass;
284 if (!klass->image->checked_module_cctor) {
285 mono_image_check_for_module_cctor (klass->image);
286 if (klass->image->has_module_cctor) {
288 MonoClass *module_klass;
289 MonoVTable *module_vtable;
291 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
293 exc = mono_error_convert_to_exception (&error);
295 mono_raise_exception (exc);
299 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
302 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
307 method = mono_class_get_cctor (klass);
310 MonoDomain *domain = vtable->domain;
311 TypeInitializationLock *lock;
312 guint32 tid = GetCurrentThreadId();
313 int do_initialization = 0;
314 MonoDomain *last_domain = NULL;
316 mono_type_initialization_lock ();
317 /* double check... */
318 if (vtable->initialized) {
319 mono_type_initialization_unlock ();
322 if (vtable->init_failed) {
323 mono_type_initialization_unlock ();
325 /* The type initialization already failed once, rethrow the same exception */
327 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
328 return get_type_init_exception_for_vtable (vtable);
330 lock = g_hash_table_lookup (type_initialization_hash, vtable);
332 /* This thread will get to do the initialization */
333 if (mono_domain_get () != domain) {
334 /* Transfer into the target domain */
335 last_domain = mono_domain_get ();
336 if (!mono_domain_set (domain, FALSE)) {
337 vtable->initialized = 1;
338 mono_type_initialization_unlock ();
340 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
341 return mono_get_exception_appdomain_unloaded ();
344 lock = g_malloc (sizeof(TypeInitializationLock));
345 mono_mutex_init_recursive (&lock->initialization_section);
346 lock->initializing_tid = tid;
347 lock->waiting_count = 1;
349 /* grab the vtable lock while this thread still owns type_initialization_section */
350 mono_mutex_lock (&lock->initialization_section);
351 g_hash_table_insert (type_initialization_hash, vtable, lock);
352 do_initialization = 1;
355 TypeInitializationLock *pending_lock;
357 if (lock->initializing_tid == tid || lock->done) {
358 mono_type_initialization_unlock ();
361 /* see if the thread doing the initialization is already blocked on this thread */
362 blocked = GUINT_TO_POINTER (lock->initializing_tid);
363 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
364 if (pending_lock->initializing_tid == tid) {
365 if (!pending_lock->done) {
366 mono_type_initialization_unlock ();
369 /* the thread doing the initialization is blocked on this thread,
370 but on a lock that has already been freed. It just hasn't got
375 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
377 ++lock->waiting_count;
378 /* record the fact that we are waiting on the initializing thread */
379 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
381 mono_type_initialization_unlock ();
383 if (do_initialization) {
384 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
386 /* If the initialization failed, mark the class as unusable. */
387 /* Avoid infinite loops */
389 (klass->image == mono_defaults.corlib &&
390 !strcmp (klass->name_space, "System") &&
391 !strcmp (klass->name, "TypeInitializationException")))) {
392 vtable->init_failed = 1;
394 if (klass->name_space && *klass->name_space)
395 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
397 full_name = g_strdup (klass->name);
398 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
402 * Store the exception object so it could be thrown on subsequent
405 mono_domain_lock (domain);
406 if (!domain->type_init_exception_hash)
407 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
408 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
409 mono_domain_unlock (domain);
413 mono_domain_set (last_domain, TRUE);
415 mono_mutex_unlock (&lock->initialization_section);
417 /* this just blocks until the initializing thread is done */
418 mono_mutex_lock (&lock->initialization_section);
419 mono_mutex_unlock (&lock->initialization_section);
422 mono_type_initialization_lock ();
423 if (lock->initializing_tid != tid)
424 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
425 --lock->waiting_count;
426 if (lock->waiting_count == 0) {
427 mono_mutex_destroy (&lock->initialization_section);
428 g_hash_table_remove (type_initialization_hash, vtable);
431 mono_memory_barrier ();
432 if (!vtable->init_failed)
433 vtable->initialized = 1;
434 mono_type_initialization_unlock ();
436 if (vtable->init_failed) {
437 /* Either we were the initializing thread or we waited for the initialization */
439 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
440 return get_type_init_exception_for_vtable (vtable);
443 vtable->initialized = 1;
450 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
452 MonoVTable *vtable = (MonoVTable*)key;
454 TypeInitializationLock *lock = (TypeInitializationLock*) value;
455 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
458 * Have to set this since it cannot be set by the normal code in
459 * mono_runtime_class_init (). In this case, the exception object is not stored,
460 * and get_type_init_exception_for_class () needs to be aware of this.
462 vtable->init_failed = 1;
463 mono_mutex_unlock (&lock->initialization_section);
464 --lock->waiting_count;
465 if (lock->waiting_count == 0) {
466 mono_mutex_destroy (&lock->initialization_section);
475 mono_release_type_locks (MonoInternalThread *thread)
477 mono_type_initialization_lock ();
478 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
479 mono_type_initialization_unlock ();
483 default_trampoline (MonoMethod *method)
489 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
491 g_assert_not_reached ();
496 #ifndef DISABLE_REMOTING
499 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
501 g_error ("remoting not installed");
505 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
509 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
511 g_assert_not_reached ();
515 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
516 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
517 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
518 static MonoImtThunkBuilder imt_thunk_builder = NULL;
519 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
520 #if (MONO_IMT_SIZE > 32)
521 #error "MONO_IMT_SIZE cannot be larger than 32"
525 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
527 memcpy (&callbacks, cbs, sizeof (*cbs));
530 MonoRuntimeCallbacks*
531 mono_get_runtime_callbacks (void)
537 mono_install_trampoline (MonoTrampoline func)
539 arch_create_jit_trampoline = func? func: default_trampoline;
543 mono_install_jump_trampoline (MonoJumpTrampoline func)
545 arch_create_jump_trampoline = func? func: default_jump_trampoline;
548 #ifndef DISABLE_REMOTING
550 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
552 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
557 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
559 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
563 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
564 imt_thunk_builder = func;
567 static MonoCompileFunc default_mono_compile_method = NULL;
570 * mono_install_compile_method:
571 * @func: function to install
573 * This is a VM internal routine
576 mono_install_compile_method (MonoCompileFunc func)
578 default_mono_compile_method = func;
582 * mono_compile_method:
583 * @method: The method to compile.
585 * This JIT-compiles the method, and returns the pointer to the native code
589 mono_compile_method (MonoMethod *method)
591 if (!default_mono_compile_method) {
592 g_error ("compile method called on uninitialized runtime");
595 return default_mono_compile_method (method);
599 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
601 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
605 mono_runtime_create_delegate_trampoline (MonoClass *klass)
607 return arch_create_delegate_trampoline (mono_domain_get (), klass);
610 static MonoFreeMethodFunc default_mono_free_method = NULL;
613 * mono_install_free_method:
614 * @func: pointer to the MonoFreeMethodFunc used to release a method
616 * This is an internal VM routine, it is used for the engines to
617 * register a handler to release the resources associated with a method.
619 * Methods are freed when no more references to the delegate that holds
623 mono_install_free_method (MonoFreeMethodFunc func)
625 default_mono_free_method = func;
629 * mono_runtime_free_method:
630 * @domain; domain where the method is hosted
631 * @method: method to release
633 * This routine is invoked to free the resources associated with
634 * a method that has been JIT compiled. This is used to discard
635 * methods that were used only temporarily (for example, used in marshalling)
639 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
641 if (default_mono_free_method != NULL)
642 default_mono_free_method (domain, method);
644 mono_method_clear_object (domain, method);
646 mono_free_method (method);
650 * The vtables in the root appdomain are assumed to be reachable by other
651 * roots, and we don't use typed allocation in the other domains.
654 /* The sync block is no longer a GC pointer */
655 #define GC_HEADER_BITMAP (0)
657 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
660 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
662 MonoClassField *field;
668 max_size = mono_class_data_size (class) / sizeof (gpointer);
670 max_size = class->instance_size / sizeof (gpointer);
671 if (max_size > size) {
672 g_assert (offset <= 0);
673 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
678 /*An Ephemeron cannot be marked by sgen*/
679 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
681 memset (bitmap, 0, size / 8);
686 for (p = class; p != NULL; p = p->parent) {
687 gpointer iter = NULL;
688 while ((field = mono_class_get_fields (p, &iter))) {
692 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
694 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
697 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
700 /* FIXME: should not happen, flag as type load error */
701 if (field->type->byref)
704 if (static_fields && field->offset == -1)
708 pos = field->offset / sizeof (gpointer);
711 type = mono_type_get_underlying_type (field->type);
712 switch (type->type) {
715 case MONO_TYPE_FNPTR:
717 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
722 if (class->image != mono_defaults.corlib)
725 case MONO_TYPE_STRING:
726 case MONO_TYPE_SZARRAY:
727 case MONO_TYPE_CLASS:
728 case MONO_TYPE_OBJECT:
729 case MONO_TYPE_ARRAY:
730 g_assert ((field->offset % sizeof(gpointer)) == 0);
732 g_assert (pos < size || pos <= max_size);
733 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
734 *max_set = MAX (*max_set, pos);
736 case MONO_TYPE_GENERICINST:
737 if (!mono_type_generic_inst_is_valuetype (type)) {
738 g_assert ((field->offset % sizeof(gpointer)) == 0);
740 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
741 *max_set = MAX (*max_set, pos);
746 case MONO_TYPE_VALUETYPE: {
747 MonoClass *fclass = mono_class_from_mono_type (field->type);
748 if (fclass->has_references) {
749 /* remove the object header */
750 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
764 case MONO_TYPE_BOOLEAN:
768 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
779 * mono_class_compute_bitmap:
781 * Mono internal function to compute a bitmap of reference fields in a class.
784 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
786 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
791 * similar to the above, but sets the bits in the bitmap for any non-ref field
792 * and ignores static fields
795 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
797 MonoClassField *field;
802 max_size = class->instance_size / sizeof (gpointer);
803 if (max_size >= size) {
804 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
807 for (p = class; p != NULL; p = p->parent) {
808 gpointer iter = NULL;
809 while ((field = mono_class_get_fields (p, &iter))) {
812 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
814 /* FIXME: should not happen, flag as type load error */
815 if (field->type->byref)
818 pos = field->offset / sizeof (gpointer);
821 type = mono_type_get_underlying_type (field->type);
822 switch (type->type) {
823 #if SIZEOF_VOID_P == 8
827 case MONO_TYPE_FNPTR:
832 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
833 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
834 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
837 #if SIZEOF_VOID_P == 4
841 case MONO_TYPE_FNPTR:
846 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
847 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
848 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
854 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
855 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
856 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
859 case MONO_TYPE_BOOLEAN:
862 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
864 case MONO_TYPE_STRING:
865 case MONO_TYPE_SZARRAY:
866 case MONO_TYPE_CLASS:
867 case MONO_TYPE_OBJECT:
868 case MONO_TYPE_ARRAY:
870 case MONO_TYPE_GENERICINST:
871 if (!mono_type_generic_inst_is_valuetype (type)) {
876 case MONO_TYPE_VALUETYPE: {
877 MonoClass *fclass = mono_class_from_mono_type (field->type);
878 /* remove the object header */
879 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
883 g_assert_not_reached ();
892 * mono_class_insecure_overlapping:
893 * check if a class with explicit layout has references and non-references
894 * fields overlapping.
896 * Returns: TRUE if it is insecure to load the type.
899 mono_class_insecure_overlapping (MonoClass *klass)
903 gsize default_bitmap [4] = {0};
905 gsize default_nrbitmap [4] = {0};
906 int i, insecure = FALSE;
909 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
910 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
912 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
913 int idx = i % (sizeof (bitmap [0]) * 8);
914 if (bitmap [idx] & nrbitmap [idx]) {
919 if (bitmap != default_bitmap)
921 if (nrbitmap != default_nrbitmap)
924 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
932 mono_string_alloc (int length)
934 return mono_string_new_size (mono_domain_get (), length);
938 mono_class_compute_gc_descriptor (MonoClass *class)
942 gsize default_bitmap [4] = {0};
943 static gboolean gcj_inited = FALSE;
948 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
949 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
950 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
951 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
953 #ifdef HAVE_GC_GCJ_MALLOC
955 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
959 #ifdef GC_REDIRECT_TO_LOCAL
960 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
961 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
963 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
964 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
969 mono_loader_unlock ();
973 mono_class_init (class);
975 if (class->gc_descr_inited)
978 class->gc_descr_inited = TRUE;
979 class->gc_descr = GC_NO_DESCRIPTOR;
981 bitmap = default_bitmap;
982 if (class == mono_defaults.string_class) {
983 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
984 } else if (class->rank) {
985 mono_class_compute_gc_descriptor (class->element_class);
986 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
988 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
989 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
990 class->name_space, class->name);*/
992 /* remove the object header */
993 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
994 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
995 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
996 class->name_space, class->name);*/
997 if (bitmap != default_bitmap)
1001 /*static int count = 0;
1004 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1005 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1007 if (class->gc_descr == GC_NO_DESCRIPTOR)
1008 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1010 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1011 if (bitmap != default_bitmap)
1017 * field_is_special_static:
1018 * @fklass: The MonoClass to look up.
1019 * @field: The MonoClassField describing the field.
1021 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1022 * SPECIAL_STATIC_NONE otherwise.
1025 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1027 MonoCustomAttrInfo *ainfo;
1029 ainfo = mono_custom_attrs_from_field (fklass, field);
1032 for (i = 0; i < ainfo->num_attrs; ++i) {
1033 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1034 if (klass->image == mono_defaults.corlib) {
1035 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1036 mono_custom_attrs_free (ainfo);
1037 return SPECIAL_STATIC_THREAD;
1039 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1040 mono_custom_attrs_free (ainfo);
1041 return SPECIAL_STATIC_CONTEXT;
1045 mono_custom_attrs_free (ainfo);
1046 return SPECIAL_STATIC_NONE;
1049 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1050 #define mix(a,b,c) { \
1051 a -= c; a ^= rot(c, 4); c += b; \
1052 b -= a; b ^= rot(a, 6); a += c; \
1053 c -= b; c ^= rot(b, 8); b += a; \
1054 a -= c; a ^= rot(c,16); c += b; \
1055 b -= a; b ^= rot(a,19); a += c; \
1056 c -= b; c ^= rot(b, 4); b += a; \
1058 #define final(a,b,c) { \
1059 c ^= b; c -= rot(b,14); \
1060 a ^= c; a -= rot(c,11); \
1061 b ^= a; b -= rot(a,25); \
1062 c ^= b; c -= rot(b,16); \
1063 a ^= c; a -= rot(c,4); \
1064 b ^= a; b -= rot(a,14); \
1065 c ^= b; c -= rot(b,24); \
1069 * mono_method_get_imt_slot:
1071 * The IMT slot is embedded into AOTed code, so this must return the same value
1072 * for the same method across all executions. This means:
1073 * - pointers shouldn't be used as hash values.
1074 * - mono_metadata_str_hash () should be used for hashing strings.
1077 mono_method_get_imt_slot (MonoMethod *method)
1079 MonoMethodSignature *sig;
1081 guint32 *hashes_start, *hashes;
1085 /* This can be used to stress tests the collision code */
1089 * We do this to simplify generic sharing. It will hurt
1090 * performance in cases where a class implements two different
1091 * instantiations of the same generic interface.
1092 * The code in build_imt_slots () depends on this.
1094 if (method->is_inflated)
1095 method = ((MonoMethodInflated*)method)->declaring;
1097 sig = mono_method_signature (method);
1098 hashes_count = sig->param_count + 4;
1099 hashes_start = malloc (hashes_count * sizeof (guint32));
1100 hashes = hashes_start;
1102 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1103 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1104 method->klass->name_space, method->klass->name, method->name);
1107 /* Initialize hashes */
1108 hashes [0] = mono_metadata_str_hash (method->klass->name);
1109 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1110 hashes [2] = mono_metadata_str_hash (method->name);
1111 hashes [3] = mono_metadata_type_hash (sig->ret);
1112 for (i = 0; i < sig->param_count; i++) {
1113 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1116 /* Setup internal state */
1117 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1119 /* Handle most of the hashes */
1120 while (hashes_count > 3) {
1129 /* Handle the last 3 hashes (all the case statements fall through) */
1130 switch (hashes_count) {
1131 case 3 : c += hashes [2];
1132 case 2 : b += hashes [1];
1133 case 1 : a += hashes [0];
1135 case 0: /* nothing left to add */
1139 free (hashes_start);
1140 /* Report the result */
1141 return c % MONO_IMT_SIZE;
1150 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1151 guint32 imt_slot = mono_method_get_imt_slot (method);
1152 MonoImtBuilderEntry *entry;
1154 if (slot_num >= 0 && imt_slot != slot_num) {
1155 /* we build just a single imt slot and this is not it */
1159 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1160 entry->key = method;
1161 entry->value.vtable_slot = vtable_slot;
1162 entry->next = imt_builder [imt_slot];
1163 if (imt_builder [imt_slot] != NULL) {
1164 entry->children = imt_builder [imt_slot]->children + 1;
1165 if (entry->children == 1) {
1166 mono_stats.imt_slots_with_collisions++;
1167 *imt_collisions_bitmap |= (1 << imt_slot);
1170 entry->children = 0;
1171 mono_stats.imt_used_slots++;
1173 imt_builder [imt_slot] = entry;
1176 char *method_name = mono_method_full_name (method, TRUE);
1177 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1178 method, method_name, imt_slot, vtable_slot, entry->children);
1179 g_free (method_name);
1186 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1188 MonoMethod *method = e->key;
1189 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1193 method->klass->name_space,
1194 method->klass->name,
1197 printf (" * %s: NULL\n", message);
1203 compare_imt_builder_entries (const void *p1, const void *p2) {
1204 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1205 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1207 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1211 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1213 int count = end - start;
1214 int chunk_start = out_array->len;
1217 for (i = start; i < end; ++i) {
1218 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1219 item->key = sorted_array [i]->key;
1220 item->value = sorted_array [i]->value;
1221 item->has_target_code = sorted_array [i]->has_target_code;
1222 item->is_equals = TRUE;
1224 item->check_target_idx = out_array->len + 1;
1226 item->check_target_idx = 0;
1227 g_ptr_array_add (out_array, item);
1230 int middle = start + count / 2;
1231 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1233 item->key = sorted_array [middle]->key;
1234 item->is_equals = FALSE;
1235 g_ptr_array_add (out_array, item);
1236 imt_emit_ir (sorted_array, start, middle, out_array);
1237 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1243 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1244 int number_of_entries = entries->children + 1;
1245 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1246 GPtrArray *result = g_ptr_array_new ();
1247 MonoImtBuilderEntry *current_entry;
1250 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1251 sorted_array [i] = current_entry;
1253 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1255 /*for (i = 0; i < number_of_entries; i++) {
1256 print_imt_entry (" sorted array:", sorted_array [i], i);
1259 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1261 free (sorted_array);
1266 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1268 if (imt_builder_entry != NULL) {
1269 if (imt_builder_entry->children == 0 && !fail_tramp) {
1270 /* No collision, return the vtable slot contents */
1271 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1273 /* Collision, build the thunk */
1274 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1277 result = imt_thunk_builder (vtable, domain,
1278 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1279 for (i = 0; i < imt_ir->len; ++i)
1280 g_free (g_ptr_array_index (imt_ir, i));
1281 g_ptr_array_free (imt_ir, TRUE);
1293 static MonoImtBuilderEntry*
1294 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1297 * LOCKING: requires the loader and domain locks.
1301 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1305 guint32 imt_collisions_bitmap = 0;
1306 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1307 int method_count = 0;
1308 gboolean record_method_count_for_max_collisions = FALSE;
1309 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1312 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1314 for (i = 0; i < klass->interface_offsets_count; ++i) {
1315 MonoClass *iface = klass->interfaces_packed [i];
1316 int interface_offset = klass->interface_offsets_packed [i];
1317 int method_slot_in_interface, vt_slot;
1319 if (mono_class_has_variant_generic_params (iface))
1320 has_variant_iface = TRUE;
1322 mono_class_setup_methods (iface);
1323 vt_slot = interface_offset;
1324 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1327 if (slot_num >= 0 && iface->is_inflated) {
1329 * The imt slot of the method is the same as for its declaring method,
1330 * see the comment in mono_method_get_imt_slot (), so we can
1331 * avoid inflating methods which will be discarded by
1332 * add_imt_builder_entry anyway.
1334 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1335 if (mono_method_get_imt_slot (method) != slot_num) {
1340 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1341 if (method->is_generic) {
1342 has_generic_virtual = TRUE;
1347 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1348 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1353 if (extra_interfaces) {
1354 int interface_offset = klass->vtable_size;
1356 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1357 MonoClass* iface = list_item->data;
1358 int method_slot_in_interface;
1359 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1360 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1362 if (method->is_generic)
1363 has_generic_virtual = TRUE;
1364 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1366 interface_offset += iface->method.count;
1369 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1370 /* overwrite the imt slot only if we're building all the entries or if
1371 * we're building this specific one
1373 if (slot_num < 0 || i == slot_num) {
1374 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1377 if (imt_builder [i]) {
1378 MonoImtBuilderEntry *entry;
1380 /* Link entries with imt_builder [i] */
1381 for (entry = entries; entry->next; entry = entry->next) {
1383 MonoMethod *method = (MonoMethod*)entry->key;
1384 char *method_name = mono_method_full_name (method, TRUE);
1385 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1386 g_free (method_name);
1389 entry->next = imt_builder [i];
1390 entries->children += imt_builder [i]->children + 1;
1392 imt_builder [i] = entries;
1395 if (has_generic_virtual || has_variant_iface) {
1397 * There might be collisions later when the the thunk is expanded.
1399 imt_collisions_bitmap |= (1 << i);
1402 * The IMT thunk might be called with an instance of one of the
1403 * generic virtual methods, so has to fallback to the IMT trampoline.
1405 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1407 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1410 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1414 if (imt_builder [i] != NULL) {
1415 int methods_in_slot = imt_builder [i]->children + 1;
1416 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1417 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1418 record_method_count_for_max_collisions = TRUE;
1420 method_count += methods_in_slot;
1424 mono_stats.imt_number_of_methods += method_count;
1425 if (record_method_count_for_max_collisions) {
1426 mono_stats.imt_method_count_when_max_collisions = method_count;
1429 for (i = 0; i < MONO_IMT_SIZE; i++) {
1430 MonoImtBuilderEntry* entry = imt_builder [i];
1431 while (entry != NULL) {
1432 MonoImtBuilderEntry* next = entry->next;
1438 /* we OR the bitmap since we may build just a single imt slot at a time */
1439 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1443 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1444 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1448 * mono_vtable_build_imt_slot:
1449 * @vtable: virtual object table struct
1450 * @imt_slot: slot in the IMT table
1452 * Fill the given @imt_slot in the IMT table of @vtable with
1453 * a trampoline or a thunk for the case of collisions.
1454 * This is part of the internal mono API.
1456 * LOCKING: Take the domain lock.
1459 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1461 gpointer *imt = (gpointer*)vtable;
1462 imt -= MONO_IMT_SIZE;
1463 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1465 /* no support for extra interfaces: the proxy objects will need
1466 * to build the complete IMT
1467 * Update and heck needs to ahppen inside the proper domain lock, as all
1468 * the changes made to a MonoVTable.
1470 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1471 mono_domain_lock (vtable->domain);
1472 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1473 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1474 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1475 mono_domain_unlock (vtable->domain);
1476 mono_loader_unlock ();
1481 * The first two free list entries both belong to the wait list: The
1482 * first entry is the pointer to the head of the list and the second
1483 * entry points to the last element. That way appending and removing
1484 * the first element are both O(1) operations.
1486 #ifdef MONO_SMALL_CONFIG
1487 #define NUM_FREE_LISTS 6
1489 #define NUM_FREE_LISTS 12
1491 #define FIRST_FREE_LIST_SIZE 64
1492 #define MAX_WAIT_LENGTH 50
1493 #define THUNK_THRESHOLD 10
1496 * LOCKING: The domain lock must be held.
1499 init_thunk_free_lists (MonoDomain *domain)
1501 if (domain->thunk_free_lists)
1503 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1507 list_index_for_size (int item_size)
1510 int size = FIRST_FREE_LIST_SIZE;
1512 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1521 * mono_method_alloc_generic_virtual_thunk:
1523 * @size: size in bytes
1525 * Allocs size bytes to be used for the code of a generic virtual
1526 * thunk. It's either allocated from the domain's code manager or
1527 * reused from a previously invalidated piece.
1529 * LOCKING: The domain lock must be held.
1532 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1534 static gboolean inited = FALSE;
1535 static int generic_virtual_thunks_size = 0;
1539 MonoThunkFreeList **l;
1541 init_thunk_free_lists (domain);
1543 size += sizeof (guint32);
1544 if (size < sizeof (MonoThunkFreeList))
1545 size = sizeof (MonoThunkFreeList);
1547 i = list_index_for_size (size);
1548 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1549 if ((*l)->size >= size) {
1550 MonoThunkFreeList *item = *l;
1552 return ((guint32*)item) + 1;
1556 /* no suitable item found - search lists of larger sizes */
1557 while (++i < NUM_FREE_LISTS) {
1558 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1561 g_assert (item->size > size);
1562 domain->thunk_free_lists [i] = item->next;
1563 return ((guint32*)item) + 1;
1566 /* still nothing found - allocate it */
1568 mono_counters_register ("Generic virtual thunk bytes",
1569 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1572 generic_virtual_thunks_size += size;
1574 p = mono_domain_code_reserve (domain, size);
1577 mono_domain_lock (domain);
1578 if (!domain->generic_virtual_thunks)
1579 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1580 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1581 mono_domain_unlock (domain);
1587 * LOCKING: The domain lock must be held.
1590 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1593 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1594 gboolean found = FALSE;
1596 mono_domain_lock (domain);
1597 if (!domain->generic_virtual_thunks)
1598 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1599 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1601 mono_domain_unlock (domain);
1604 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1606 init_thunk_free_lists (domain);
1608 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1609 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1610 int length = item->length;
1613 /* unlink the first item from the wait list */
1614 domain->thunk_free_lists [0] = item->next;
1615 domain->thunk_free_lists [0]->length = length - 1;
1617 i = list_index_for_size (item->size);
1619 /* put it in the free list */
1620 item->next = domain->thunk_free_lists [i];
1621 domain->thunk_free_lists [i] = item;
1625 if (domain->thunk_free_lists [1]) {
1626 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1627 domain->thunk_free_lists [0]->length++;
1629 g_assert (!domain->thunk_free_lists [0]);
1631 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1632 domain->thunk_free_lists [0]->length = 1;
1636 typedef struct _GenericVirtualCase {
1640 struct _GenericVirtualCase *next;
1641 } GenericVirtualCase;
1644 * get_generic_virtual_entries:
1646 * Return IMT entries for the generic virtual method instances and
1647 * variant interface methods for vtable slot
1650 static MonoImtBuilderEntry*
1651 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1653 GenericVirtualCase *list;
1654 MonoImtBuilderEntry *entries;
1656 mono_domain_lock (domain);
1657 if (!domain->generic_virtual_cases)
1658 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1660 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1663 for (; list; list = list->next) {
1664 MonoImtBuilderEntry *entry;
1666 if (list->count < THUNK_THRESHOLD)
1669 entry = g_new0 (MonoImtBuilderEntry, 1);
1670 entry->key = list->method;
1671 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1672 entry->has_target_code = 1;
1674 entry->children = entries->children + 1;
1675 entry->next = entries;
1679 mono_domain_unlock (domain);
1681 /* FIXME: Leaking memory ? */
1686 * mono_method_add_generic_virtual_invocation:
1688 * @vtable_slot: pointer to the vtable slot
1689 * @method: the inflated generic virtual method
1690 * @code: the method's code
1692 * Registers a call via unmanaged code to a generic virtual method
1693 * instantiation or variant interface method. If the number of calls reaches a threshold
1694 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1695 * virtual method thunk.
1698 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1699 gpointer *vtable_slot,
1700 MonoMethod *method, gpointer code)
1702 static gboolean inited = FALSE;
1703 static int num_added = 0;
1705 GenericVirtualCase *gvc, *list;
1706 MonoImtBuilderEntry *entries;
1710 mono_domain_lock (domain);
1711 if (!domain->generic_virtual_cases)
1712 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1714 /* Check whether the case was already added */
1715 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1718 if (gvc->method == method)
1723 /* If not found, make a new one */
1725 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1726 gvc->method = method;
1729 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1731 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1734 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1740 if (++gvc->count == THUNK_THRESHOLD) {
1741 gpointer *old_thunk = *vtable_slot;
1742 gpointer vtable_trampoline = NULL;
1743 gpointer imt_trampoline = NULL;
1745 if ((gpointer)vtable_slot < (gpointer)vtable) {
1746 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1747 int imt_slot = MONO_IMT_SIZE + displacement;
1749 /* Force the rebuild of the thunk at the next call */
1750 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1751 *vtable_slot = imt_trampoline;
1753 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1755 entries = get_generic_virtual_entries (domain, vtable_slot);
1757 sorted = imt_sort_slot_entries (entries);
1759 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1763 MonoImtBuilderEntry *next = entries->next;
1768 for (i = 0; i < sorted->len; ++i)
1769 g_free (g_ptr_array_index (sorted, i));
1770 g_ptr_array_free (sorted, TRUE);
1773 #ifndef __native_client__
1774 /* We don't re-use any thunks as there is a lot of overhead */
1775 /* to deleting and re-using code in Native Client. */
1776 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1777 invalidate_generic_virtual_thunk (domain, old_thunk);
1781 mono_domain_unlock (domain);
1784 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1787 * mono_class_vtable:
1788 * @domain: the application domain
1789 * @class: the class to initialize
1791 * VTables are domain specific because we create domain specific code, and
1792 * they contain the domain specific static class data.
1793 * On failure, NULL is returned, and class->exception_type is set.
1796 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1798 return mono_class_vtable_full (domain, class, FALSE);
1802 * mono_class_vtable_full:
1803 * @domain: the application domain
1804 * @class: the class to initialize
1805 * @raise_on_error if an exception should be raised on failure or not
1807 * VTables are domain specific because we create domain specific code, and
1808 * they contain the domain specific static class data.
1811 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1813 MonoClassRuntimeInfo *runtime_info;
1817 if (class->exception_type) {
1819 mono_raise_exception (mono_class_get_exception_for_failure (class));
1823 /* this check can be inlined in jitted code, too */
1824 runtime_info = class->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1827 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1831 * mono_class_try_get_vtable:
1832 * @domain: the application domain
1833 * @class: the class to initialize
1835 * This function tries to get the associated vtable from @class if
1836 * it was already created.
1839 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1841 MonoClassRuntimeInfo *runtime_info;
1845 runtime_info = class->runtime_info;
1846 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1847 return runtime_info->domain_vtables [domain->domain_id];
1852 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1854 size_t alloc_offset;
1857 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1858 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1859 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1861 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1862 g_assert ((imt_table_bytes & 7) == 4);
1869 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1873 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1876 MonoClassRuntimeInfo *runtime_info, *old_info;
1877 MonoClassField *field;
1879 int i, vtable_slots;
1880 size_t imt_table_bytes;
1882 guint32 vtable_size, class_size;
1884 gpointer *interface_offsets;
1886 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1887 mono_domain_lock (domain);
1888 runtime_info = class->runtime_info;
1889 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1890 mono_domain_unlock (domain);
1891 mono_loader_unlock ();
1892 return runtime_info->domain_vtables [domain->domain_id];
1894 if (!class->inited || class->exception_type) {
1895 if (!mono_class_init (class) || class->exception_type) {
1896 mono_domain_unlock (domain);
1897 mono_loader_unlock ();
1899 mono_raise_exception (mono_class_get_exception_for_failure (class));
1904 /* Array types require that their element type be valid*/
1905 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1906 MonoClass *element_class = class->element_class;
1907 if (!element_class->inited)
1908 mono_class_init (element_class);
1910 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1911 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1912 mono_class_setup_vtable (element_class);
1914 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1915 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1916 if (class->exception_type == MONO_EXCEPTION_NONE)
1917 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1918 mono_domain_unlock (domain);
1919 mono_loader_unlock ();
1921 mono_raise_exception (mono_class_get_exception_for_failure (class));
1927 * For some classes, mono_class_init () already computed class->vtable_size, and
1928 * that is all that is needed because of the vtable trampolines.
1930 if (!class->vtable_size)
1931 mono_class_setup_vtable (class);
1933 if (class->generic_class && !class->vtable)
1934 mono_class_check_vtable_constraints (class, NULL);
1936 /* Initialize klass->has_finalize */
1937 mono_class_has_finalizer (class);
1939 if (class->exception_type) {
1940 mono_domain_unlock (domain);
1941 mono_loader_unlock ();
1943 mono_raise_exception (mono_class_get_exception_for_failure (class));
1947 vtable_slots = class->vtable_size;
1948 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1949 class_size = mono_class_data_size (class);
1954 if (class->interface_offsets_count) {
1955 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1956 mono_stats.imt_number_of_tables++;
1957 mono_stats.imt_tables_size += imt_table_bytes;
1959 imt_table_bytes = 0;
1962 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1965 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1967 mono_stats.used_class_count++;
1968 mono_stats.class_vtable_size += vtable_size;
1970 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1971 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1972 g_assert (!((gsize)vt & 7));
1975 vt->rank = class->rank;
1976 vt->domain = domain;
1978 mono_class_compute_gc_descriptor (class);
1980 * We can't use typed allocation in the non-root domains, since the
1981 * collector needs the GC descriptor stored in the vtable even after
1982 * the mempool containing the vtable is destroyed when the domain is
1983 * unloaded. An alternative might be to allocate vtables in the GC
1984 * heap, but this does not seem to work (it leads to crashes inside
1985 * libgc). If that approach is tried, two gc descriptors need to be
1986 * allocated for each class: one for the root domain, and one for all
1987 * other domains. The second descriptor should contain a bit for the
1988 * vtable field in MonoObject, since we can no longer assume the
1989 * vtable is reachable by other roots after the appdomain is unloaded.
1991 #ifdef HAVE_BOEHM_GC
1992 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1993 vt->gc_descr = GC_NO_DESCRIPTOR;
1996 vt->gc_descr = class->gc_descr;
1998 gc_bits = mono_gc_get_vtable_bits (class);
1999 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2001 vt->gc_bits = gc_bits;
2004 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2005 if (class->has_static_refs) {
2006 gpointer statics_gc_descr;
2008 gsize default_bitmap [4] = {0};
2011 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2012 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2013 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2014 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2015 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2016 if (bitmap != default_bitmap)
2019 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2021 vt->has_static_fields = TRUE;
2022 mono_stats.class_static_data_size += class_size;
2026 while ((field = mono_class_get_fields (class, &iter))) {
2027 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2029 if (mono_field_is_deleted (field))
2031 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2032 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2033 if (special_static != SPECIAL_STATIC_NONE) {
2034 guint32 size, offset;
2036 gsize default_bitmap [4] = {0};
2041 if (mono_type_is_reference (field->type)) {
2042 default_bitmap [0] = 1;
2044 bitmap = default_bitmap;
2045 } else if (mono_type_is_struct (field->type)) {
2046 fclass = mono_class_from_mono_type (field->type);
2047 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2048 numbits = max_set + 1;
2050 default_bitmap [0] = 0;
2052 bitmap = default_bitmap;
2054 size = mono_type_size (field->type, &align);
2055 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2056 if (!domain->special_static_fields)
2057 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2058 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2059 if (bitmap != default_bitmap)
2062 * This marks the field as special static to speed up the
2063 * checks in mono_field_static_get/set_value ().
2069 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2070 MonoClass *fklass = mono_class_from_mono_type (field->type);
2071 const char *data = mono_field_get_data (field);
2073 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2074 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2075 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2078 if (fklass->valuetype) {
2079 memcpy (t, data, mono_class_value_size (fklass, NULL));
2081 /* it's a pointer type: add check */
2082 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2089 vt->max_interface_id = class->max_interface_id;
2090 vt->interface_bitmap = class->interface_bitmap;
2092 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2093 // class->name, class->interface_offsets_count);
2095 if (! ARCH_USE_IMT) {
2096 /* initialize interface offsets */
2097 for (i = 0; i < class->interface_offsets_count; ++i) {
2098 int interface_id = class->interfaces_packed [i]->interface_id;
2099 int slot = class->interface_offsets_packed [i];
2100 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2104 /* Initialize vtable */
2105 if (callbacks.get_vtable_trampoline) {
2106 // This also covers the AOT case
2107 for (i = 0; i < class->vtable_size; ++i) {
2108 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2111 mono_class_setup_vtable (class);
2113 for (i = 0; i < class->vtable_size; ++i) {
2116 if ((cm = class->vtable [i]))
2117 vt->vtable [i] = arch_create_jit_trampoline (cm);
2121 if (ARCH_USE_IMT && imt_table_bytes) {
2122 /* Now that the vtable is full, we can actually fill up the IMT */
2123 if (callbacks.get_imt_trampoline) {
2124 /* lazy construction of the IMT entries enabled */
2125 for (i = 0; i < MONO_IMT_SIZE; ++i)
2126 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2128 build_imt (class, vt, domain, interface_offsets, NULL);
2133 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2134 * re-acquire them and check if another thread has created the vtable in the meantime.
2136 /* Special case System.MonoType to avoid infinite recursion */
2137 if (class != mono_defaults.monotype_class) {
2138 /*FIXME check for OOM*/
2139 vt->type = mono_type_get_object (domain, &class->byval_arg);
2140 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2141 /* This is unregistered in
2142 unregister_vtable_reflection_type() in
2144 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2147 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2149 /* class_vtable_array keeps an array of created vtables
2151 g_ptr_array_add (domain->class_vtable_array, vt);
2152 /* class->runtime_info is protected by the loader lock, both when
2153 * it it enlarged and when it is stored info.
2157 * Store the vtable in class->runtime_info.
2158 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2160 mono_memory_barrier ();
2162 old_info = class->runtime_info;
2163 if (old_info && old_info->max_domain >= domain->domain_id) {
2164 /* someone already created a large enough runtime info */
2165 old_info->domain_vtables [domain->domain_id] = vt;
2167 int new_size = domain->domain_id;
2169 new_size = MAX (new_size, old_info->max_domain);
2171 /* make the new size a power of two */
2173 while (new_size > i)
2176 /* this is a bounded memory retention issue: may want to
2177 * handle it differently when we'll have a rcu-like system.
2179 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2180 runtime_info->max_domain = new_size - 1;
2181 /* copy the stuff from the older info */
2183 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2185 runtime_info->domain_vtables [domain->domain_id] = vt;
2187 mono_memory_barrier ();
2188 class->runtime_info = runtime_info;
2191 if (class == mono_defaults.monotype_class) {
2192 /*FIXME check for OOM*/
2193 vt->type = mono_type_get_object (domain, &class->byval_arg);
2194 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2195 /* This is unregistered in
2196 unregister_vtable_reflection_type() in
2198 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2201 mono_domain_unlock (domain);
2202 mono_loader_unlock ();
2204 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2205 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2206 mono_raise_exception (mono_class_get_exception_for_failure (class));
2208 /* make sure the parent is initialized */
2209 /*FIXME shouldn't this fail the current type?*/
2211 mono_class_vtable_full (domain, class->parent, raise_on_error);
2216 #ifndef DISABLE_REMOTING
2218 * mono_class_proxy_vtable:
2219 * @domain: the application domain
2220 * @remove_class: the remote class
2222 * Creates a vtable for transparent proxies. It is basically
2223 * a copy of the real vtable of the class wrapped in @remote_class,
2224 * but all function pointers invoke the remoting functions, and
2225 * vtable->klass points to the transparent proxy class, and not to @class.
2228 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2231 MonoVTable *vt, *pvt;
2232 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2234 GSList *extra_interfaces = NULL;
2235 MonoClass *class = remote_class->proxy_class;
2236 gpointer *interface_offsets;
2239 size_t imt_table_bytes;
2241 #ifdef COMPRESSED_INTERFACE_BITMAP
2245 vt = mono_class_vtable (domain, class);
2246 g_assert (vt); /*FIXME property handle failure*/
2247 max_interface_id = vt->max_interface_id;
2249 /* Calculate vtable space for extra interfaces */
2250 for (j = 0; j < remote_class->interface_count; j++) {
2251 MonoClass* iclass = remote_class->interfaces[j];
2255 /*FIXME test for interfaces with variant generic arguments*/
2256 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2257 continue; /* interface implemented by the class */
2258 if (g_slist_find (extra_interfaces, iclass))
2261 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2263 method_count = mono_class_num_methods (iclass);
2265 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2266 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2268 for (i = 0; i < ifaces->len; ++i) {
2269 MonoClass *ic = g_ptr_array_index (ifaces, i);
2270 /*FIXME test for interfaces with variant generic arguments*/
2271 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2272 continue; /* interface implemented by the class */
2273 if (g_slist_find (extra_interfaces, ic))
2275 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2276 method_count += mono_class_num_methods (ic);
2278 g_ptr_array_free (ifaces, TRUE);
2281 extra_interface_vtsize += method_count * sizeof (gpointer);
2282 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2286 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2287 mono_stats.imt_number_of_tables++;
2288 mono_stats.imt_tables_size += imt_table_bytes;
2290 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2293 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2295 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2297 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2298 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2299 g_assert (!((gsize)pvt & 7));
2301 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2303 pvt->klass = mono_defaults.transparent_proxy_class;
2304 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2305 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2307 /* initialize vtable */
2308 mono_class_setup_vtable (class);
2309 for (i = 0; i < class->vtable_size; ++i) {
2312 if ((cm = class->vtable [i]))
2313 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2315 pvt->vtable [i] = NULL;
2318 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2319 /* create trampolines for abstract methods */
2320 for (k = class; k; k = k->parent) {
2322 gpointer iter = NULL;
2323 while ((m = mono_class_get_methods (k, &iter)))
2324 if (!pvt->vtable [m->slot])
2325 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2329 pvt->max_interface_id = max_interface_id;
2330 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2331 #ifdef COMPRESSED_INTERFACE_BITMAP
2332 bitmap = g_malloc0 (bsize);
2334 bitmap = mono_domain_alloc0 (domain, bsize);
2337 if (! ARCH_USE_IMT) {
2338 /* initialize interface offsets */
2339 for (i = 0; i < class->interface_offsets_count; ++i) {
2340 int interface_id = class->interfaces_packed [i]->interface_id;
2341 int slot = class->interface_offsets_packed [i];
2342 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2345 for (i = 0; i < class->interface_offsets_count; ++i) {
2346 int interface_id = class->interfaces_packed [i]->interface_id;
2347 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2350 if (extra_interfaces) {
2351 int slot = class->vtable_size;
2357 /* Create trampolines for the methods of the interfaces */
2358 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2359 interf = list_item->data;
2361 if (! ARCH_USE_IMT) {
2362 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2364 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2368 while ((cm = mono_class_get_methods (interf, &iter)))
2369 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2371 slot += mono_class_num_methods (interf);
2373 if (! ARCH_USE_IMT) {
2374 g_slist_free (extra_interfaces);
2379 /* Now that the vtable is full, we can actually fill up the IMT */
2380 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2381 if (extra_interfaces) {
2382 g_slist_free (extra_interfaces);
2386 #ifdef COMPRESSED_INTERFACE_BITMAP
2387 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2388 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2389 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2392 pvt->interface_bitmap = bitmap;
2397 #endif /* DISABLE_REMOTING */
2400 * mono_class_field_is_special_static:
2402 * Returns whether @field is a thread/context static field.
2405 mono_class_field_is_special_static (MonoClassField *field)
2407 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2409 if (mono_field_is_deleted (field))
2411 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2412 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2419 * mono_class_field_get_special_static_type:
2420 * @field: The MonoClassField describing the field.
2422 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2423 * SPECIAL_STATIC_NONE otherwise.
2426 mono_class_field_get_special_static_type (MonoClassField *field)
2428 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2429 return SPECIAL_STATIC_NONE;
2430 if (mono_field_is_deleted (field))
2431 return SPECIAL_STATIC_NONE;
2432 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2433 return field_is_special_static (field->parent, field);
2434 return SPECIAL_STATIC_NONE;
2438 * mono_class_has_special_static_fields:
2440 * Returns whenever @klass has any thread/context static fields.
2443 mono_class_has_special_static_fields (MonoClass *klass)
2445 MonoClassField *field;
2449 while ((field = mono_class_get_fields (klass, &iter))) {
2450 g_assert (field->parent == klass);
2451 if (mono_class_field_is_special_static (field))
2458 #ifndef DISABLE_REMOTING
2460 * create_remote_class_key:
2461 * Creates an array of pointers that can be used as a hash key for a remote class.
2462 * The first element of the array is the number of pointers.
2465 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2470 if (remote_class == NULL) {
2471 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2472 key = g_malloc (sizeof(gpointer) * 3);
2473 key [0] = GINT_TO_POINTER (2);
2474 key [1] = mono_defaults.marshalbyrefobject_class;
2475 key [2] = extra_class;
2477 key = g_malloc (sizeof(gpointer) * 2);
2478 key [0] = GINT_TO_POINTER (1);
2479 key [1] = extra_class;
2482 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2483 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2484 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2485 key [1] = remote_class->proxy_class;
2487 // Keep the list of interfaces sorted
2488 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2489 if (extra_class && remote_class->interfaces [i] > extra_class) {
2490 key [j++] = extra_class;
2493 key [j] = remote_class->interfaces [i];
2496 key [j] = extra_class;
2498 // Replace the old class. The interface list is the same
2499 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2500 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2501 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2502 for (i = 0; i < remote_class->interface_count; i++)
2503 key [2 + i] = remote_class->interfaces [i];
2511 * copy_remote_class_key:
2513 * Make a copy of KEY in the domain and return the copy.
2516 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2518 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2519 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2521 memcpy (mp_key, key, key_size);
2527 * mono_remote_class:
2528 * @domain: the application domain
2529 * @class_name: name of the remote class
2531 * Creates and initializes a MonoRemoteClass object for a remote type.
2533 * Can raise an exception on failure.
2536 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2539 MonoRemoteClass *rc;
2540 gpointer* key, *mp_key;
2543 key = create_remote_class_key (NULL, proxy_class);
2545 mono_domain_lock (domain);
2546 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2550 mono_domain_unlock (domain);
2554 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2555 if (!mono_error_ok (&error)) {
2557 mono_domain_unlock (domain);
2558 mono_error_raise_exception (&error);
2561 mp_key = copy_remote_class_key (domain, key);
2565 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2566 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2567 rc->interface_count = 1;
2568 rc->interfaces [0] = proxy_class;
2569 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2571 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2572 rc->interface_count = 0;
2573 rc->proxy_class = proxy_class;
2576 rc->default_vtable = NULL;
2577 rc->xdomain_vtable = NULL;
2578 rc->proxy_class_name = name;
2579 #ifndef DISABLE_PERFCOUNTERS
2580 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2583 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2585 mono_domain_unlock (domain);
2590 * clone_remote_class:
2591 * Creates a copy of the remote_class, adding the provided class or interface
2593 static MonoRemoteClass*
2594 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2596 MonoRemoteClass *rc;
2597 gpointer* key, *mp_key;
2599 key = create_remote_class_key (remote_class, extra_class);
2600 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2606 mp_key = copy_remote_class_key (domain, key);
2610 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2612 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2613 rc->proxy_class = remote_class->proxy_class;
2614 rc->interface_count = remote_class->interface_count + 1;
2616 // Keep the list of interfaces sorted, since the hash key of
2617 // the remote class depends on this
2618 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2619 if (remote_class->interfaces [i] > extra_class && i == j)
2620 rc->interfaces [j++] = extra_class;
2621 rc->interfaces [j] = remote_class->interfaces [i];
2624 rc->interfaces [j] = extra_class;
2626 // Replace the old class. The interface array is the same
2627 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2628 rc->proxy_class = extra_class;
2629 rc->interface_count = remote_class->interface_count;
2630 if (rc->interface_count > 0)
2631 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2634 rc->default_vtable = NULL;
2635 rc->xdomain_vtable = NULL;
2636 rc->proxy_class_name = remote_class->proxy_class_name;
2638 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2644 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2646 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2647 mono_domain_lock (domain);
2648 if (rp->target_domain_id != -1) {
2649 if (remote_class->xdomain_vtable == NULL)
2650 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2651 mono_domain_unlock (domain);
2652 mono_loader_unlock ();
2653 return remote_class->xdomain_vtable;
2655 if (remote_class->default_vtable == NULL) {
2658 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2659 klass = mono_class_from_mono_type (type);
2661 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)))
2662 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2665 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2668 mono_domain_unlock (domain);
2669 mono_loader_unlock ();
2670 return remote_class->default_vtable;
2674 * mono_upgrade_remote_class:
2675 * @domain: the application domain
2676 * @tproxy: the proxy whose remote class has to be upgraded.
2677 * @klass: class to which the remote class can be casted.
2679 * Updates the vtable of the remote class by adding the necessary method slots
2680 * and interface offsets so it can be safely casted to klass. klass can be a
2681 * class or an interface.
2684 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2686 MonoTransparentProxy *tproxy;
2687 MonoRemoteClass *remote_class;
2688 gboolean redo_vtable;
2690 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2691 mono_domain_lock (domain);
2693 tproxy = (MonoTransparentProxy*) proxy_object;
2694 remote_class = tproxy->remote_class;
2696 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2699 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2700 if (remote_class->interfaces [i] == klass)
2701 redo_vtable = FALSE;
2704 redo_vtable = (remote_class->proxy_class != klass);
2708 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2709 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2712 mono_domain_unlock (domain);
2713 mono_loader_unlock ();
2715 #endif /* DISABLE_REMOTING */
2719 * mono_object_get_virtual_method:
2720 * @obj: object to operate on.
2723 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2724 * the instance of a callvirt of method.
2727 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2730 MonoMethod **vtable;
2731 gboolean is_proxy = FALSE;
2732 MonoMethod *res = NULL;
2734 klass = mono_object_class (obj);
2735 #ifndef DISABLE_REMOTING
2736 if (klass == mono_defaults.transparent_proxy_class) {
2737 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2742 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2745 mono_class_setup_vtable (klass);
2746 vtable = klass->vtable;
2748 if (method->slot == -1) {
2749 /* method->slot might not be set for instances of generic methods */
2750 if (method->is_inflated) {
2751 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2752 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2755 g_assert_not_reached ();
2759 /* check method->slot is a valid index: perform isinstance? */
2760 if (method->slot != -1) {
2761 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2763 gboolean variance_used = FALSE;
2764 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2765 g_assert (iface_offset > 0);
2766 res = vtable [iface_offset + method->slot];
2769 res = vtable [method->slot];
2773 #ifndef DISABLE_REMOTING
2775 /* It may be an interface, abstract class method or generic method */
2776 if (!res || mono_method_signature (res)->generic_param_count)
2779 /* generic methods demand invoke_with_check */
2780 if (mono_method_signature (res)->generic_param_count)
2781 res = mono_marshal_get_remoting_invoke_with_check (res);
2784 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2785 res = mono_cominterop_get_invoke (res);
2788 res = mono_marshal_get_remoting_invoke (res);
2793 if (method->is_inflated) {
2795 /* Have to inflate the result */
2796 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2797 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2807 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2809 g_error ("runtime invoke called on uninitialized runtime");
2813 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2816 * mono_runtime_invoke:
2817 * @method: method to invoke
2818 * @obJ: object instance
2819 * @params: arguments to the method
2820 * @exc: exception information.
2822 * Invokes the method represented by @method on the object @obj.
2824 * obj is the 'this' pointer, it should be NULL for static
2825 * methods, a MonoObject* for object instances and a pointer to
2826 * the value type for value types.
2828 * The params array contains the arguments to the method with the
2829 * same convention: MonoObject* pointers for object instances and
2830 * pointers to the value type otherwise.
2832 * From unmanaged code you'll usually use the
2833 * mono_runtime_invoke() variant.
2835 * Note that this function doesn't handle virtual methods for
2836 * you, it will exec the exact method you pass: we still need to
2837 * expose a function to lookup the derived class implementation
2838 * of a virtual method (there are examples of this in the code,
2841 * You can pass NULL as the exc argument if you don't want to
2842 * catch exceptions, otherwise, *exc will be set to the exception
2843 * thrown, if any. if an exception is thrown, you can't use the
2844 * MonoObject* result from the function.
2846 * If the method returns a value type, it is boxed in an object
2850 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2854 if (mono_runtime_get_no_exec ())
2855 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2857 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2858 mono_profiler_method_start_invoke (method);
2860 result = default_mono_runtime_invoke (method, obj, params, exc);
2862 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2863 mono_profiler_method_end_invoke (method);
2869 * mono_method_get_unmanaged_thunk:
2870 * @method: method to generate a thunk for.
2872 * Returns an unmanaged->managed thunk that can be used to call
2873 * a managed method directly from C.
2875 * The thunk's C signature closely matches the managed signature:
2877 * C#: public bool Equals (object obj);
2878 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2879 * MonoObject*, MonoException**);
2881 * The 1st ("this") parameter must not be used with static methods:
2883 * C#: public static bool ReferenceEquals (object a, object b);
2884 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2887 * The last argument must be a non-null pointer of a MonoException* pointer.
2888 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2889 * exception has been thrown in managed code. Otherwise it will point
2890 * to the MonoException* caught by the thunk. In this case, the result of
2891 * the thunk is undefined:
2893 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2894 * MonoException *ex = NULL;
2895 * Equals func = mono_method_get_unmanaged_thunk (method);
2896 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2898 * // handle exception
2901 * The calling convention of the thunk matches the platform's default
2902 * convention. This means that under Windows, C declarations must
2903 * contain the __stdcall attribute:
2905 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2906 * MonoObject*, MonoException**);
2910 * Value type arguments and return values are treated as they were objects:
2912 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2913 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2915 * Arguments must be properly boxed upon trunk's invocation, while return
2916 * values must be unboxed.
2919 mono_method_get_unmanaged_thunk (MonoMethod *method)
2921 method = mono_marshal_get_thunk_invoke_wrapper (method);
2922 return mono_compile_method (method);
2926 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2930 /* object fields cannot be byref, so we don't need a
2932 gpointer *p = (gpointer*)dest;
2939 case MONO_TYPE_BOOLEAN:
2941 case MONO_TYPE_U1: {
2942 guint8 *p = (guint8*)dest;
2943 *p = value ? *(guint8*)value : 0;
2948 case MONO_TYPE_CHAR: {
2949 guint16 *p = (guint16*)dest;
2950 *p = value ? *(guint16*)value : 0;
2953 #if SIZEOF_VOID_P == 4
2958 case MONO_TYPE_U4: {
2959 gint32 *p = (gint32*)dest;
2960 *p = value ? *(gint32*)value : 0;
2963 #if SIZEOF_VOID_P == 8
2968 case MONO_TYPE_U8: {
2969 gint64 *p = (gint64*)dest;
2970 *p = value ? *(gint64*)value : 0;
2973 case MONO_TYPE_R4: {
2974 float *p = (float*)dest;
2975 *p = value ? *(float*)value : 0;
2978 case MONO_TYPE_R8: {
2979 double *p = (double*)dest;
2980 *p = value ? *(double*)value : 0;
2983 case MONO_TYPE_STRING:
2984 case MONO_TYPE_SZARRAY:
2985 case MONO_TYPE_CLASS:
2986 case MONO_TYPE_OBJECT:
2987 case MONO_TYPE_ARRAY:
2988 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2990 case MONO_TYPE_FNPTR:
2991 case MONO_TYPE_PTR: {
2992 gpointer *p = (gpointer*)dest;
2993 *p = deref_pointer? *(gpointer*)value: value;
2996 case MONO_TYPE_VALUETYPE:
2997 /* note that 't' and 'type->type' can be different */
2998 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2999 t = mono_class_enum_basetype (type->data.klass)->type;
3002 MonoClass *class = mono_class_from_mono_type (type);
3003 int size = mono_class_value_size (class, NULL);
3005 mono_gc_bzero_atomic (dest, size);
3007 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3010 case MONO_TYPE_GENERICINST:
3011 t = type->data.generic_class->container_class->byval_arg.type;
3014 g_error ("got type %x", type->type);
3019 * mono_field_set_value:
3020 * @obj: Instance object
3021 * @field: MonoClassField describing the field to set
3022 * @value: The value to be set
3024 * Sets the value of the field described by @field in the object instance @obj
3025 * to the value passed in @value. This method should only be used for instance
3026 * fields. For static fields, use mono_field_static_set_value.
3028 * The value must be on the native format of the field type.
3031 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3035 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3037 dest = (char*)obj + field->offset;
3038 mono_copy_value (field->type, dest, value, FALSE);
3042 * mono_field_static_set_value:
3043 * @field: MonoClassField describing the field to set
3044 * @value: The value to be set
3046 * Sets the value of the static field described by @field
3047 * to the value passed in @value.
3049 * The value must be on the native format of the field type.
3052 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3056 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3057 /* you cant set a constant! */
3058 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3060 if (field->offset == -1) {
3061 /* Special static */
3064 mono_domain_lock (vt->domain);
3065 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3066 mono_domain_unlock (vt->domain);
3067 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3069 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3071 mono_copy_value (field->type, dest, value, FALSE);
3075 * mono_vtable_get_static_field_data:
3077 * Internal use function: return a pointer to the memory holding the static fields
3078 * for a class or NULL if there are no static fields.
3079 * This is exported only for use by the debugger.
3082 mono_vtable_get_static_field_data (MonoVTable *vt)
3084 if (!vt->has_static_fields)
3086 return vt->vtable [vt->klass->vtable_size];
3090 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3094 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3095 if (field->offset == -1) {
3096 /* Special static */
3099 mono_domain_lock (vt->domain);
3100 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3101 mono_domain_unlock (vt->domain);
3102 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3104 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3107 src = (guint8*)obj + field->offset;
3114 * mono_field_get_value:
3115 * @obj: Object instance
3116 * @field: MonoClassField describing the field to fetch information from
3117 * @value: pointer to the location where the value will be stored
3119 * Use this routine to get the value of the field @field in the object
3122 * The pointer provided by value must be of the field type, for reference
3123 * types this is a MonoObject*, for value types its the actual pointer to
3128 * mono_field_get_value (obj, int_field, &i);
3131 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3137 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3139 src = (char*)obj + field->offset;
3140 mono_copy_value (field->type, value, src, TRUE);
3144 * mono_field_get_value_object:
3145 * @domain: domain where the object will be created (if boxing)
3146 * @field: MonoClassField describing the field to fetch information from
3147 * @obj: The object instance for the field.
3149 * Returns: a new MonoObject with the value from the given field. If the
3150 * field represents a value type, the value is boxed.
3154 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3158 MonoVTable *vtable = NULL;
3160 gboolean is_static = FALSE;
3161 gboolean is_ref = FALSE;
3162 gboolean is_literal = FALSE;
3163 gboolean is_ptr = FALSE;
3165 MonoType *type = mono_field_get_type_checked (field, &error);
3167 if (!mono_error_ok (&error))
3168 mono_error_raise_exception (&error);
3170 switch (type->type) {
3171 case MONO_TYPE_STRING:
3172 case MONO_TYPE_OBJECT:
3173 case MONO_TYPE_CLASS:
3174 case MONO_TYPE_ARRAY:
3175 case MONO_TYPE_SZARRAY:
3180 case MONO_TYPE_BOOLEAN:
3183 case MONO_TYPE_CHAR:
3192 case MONO_TYPE_VALUETYPE:
3193 is_ref = type->byref;
3195 case MONO_TYPE_GENERICINST:
3196 is_ref = !mono_type_generic_inst_is_valuetype (type);
3202 g_error ("type 0x%x not handled in "
3203 "mono_field_get_value_object", type->type);
3207 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3210 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3214 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3215 if (!vtable->initialized)
3216 mono_runtime_class_init (vtable);
3224 get_default_field_value (domain, field, &o);
3225 } else if (is_static) {
3226 mono_field_static_get_value (vtable, field, &o);
3228 mono_field_get_value (obj, field, &o);
3234 static MonoMethod *m;
3240 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3241 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3247 get_default_field_value (domain, field, v);
3248 } else if (is_static) {
3249 mono_field_static_get_value (vtable, field, v);
3251 mono_field_get_value (obj, field, v);
3254 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3255 args [0] = ptr ? *ptr : NULL;
3256 args [1] = mono_type_get_object (mono_domain_get (), type);
3258 return mono_runtime_invoke (m, NULL, args, NULL);
3261 /* boxed value type */
3262 klass = mono_class_from_mono_type (type);
3264 if (mono_class_is_nullable (klass))
3265 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3267 o = mono_object_new (domain, klass);
3268 v = ((gchar *) o) + sizeof (MonoObject);
3271 get_default_field_value (domain, field, v);
3272 } else if (is_static) {
3273 mono_field_static_get_value (vtable, field, v);
3275 mono_field_get_value (obj, field, v);
3282 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3285 const char *p = blob;
3286 mono_metadata_decode_blob_size (p, &p);
3289 case MONO_TYPE_BOOLEAN:
3292 *(guint8 *) value = *p;
3294 case MONO_TYPE_CHAR:
3297 *(guint16*) value = read16 (p);
3301 *(guint32*) value = read32 (p);
3305 *(guint64*) value = read64 (p);
3308 readr4 (p, (float*) value);
3311 readr8 (p, (double*) value);
3313 case MONO_TYPE_STRING:
3314 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3316 case MONO_TYPE_CLASS:
3317 *(gpointer*) value = NULL;
3321 g_warning ("type 0x%02x should not be in constant table", type);
3327 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3329 MonoTypeEnum def_type;
3332 data = mono_class_get_field_default_value (field, &def_type);
3333 mono_get_constant_value_from_blob (domain, def_type, data, value);
3337 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3341 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3343 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3344 get_default_field_value (vt->domain, field, value);
3348 if (field->offset == -1) {
3349 /* Special static */
3350 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3351 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3353 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3355 mono_copy_value (field->type, value, src, TRUE);
3359 * mono_field_static_get_value:
3360 * @vt: vtable to the object
3361 * @field: MonoClassField describing the field to fetch information from
3362 * @value: where the value is returned
3364 * Use this routine to get the value of the static field @field value.
3366 * The pointer provided by value must be of the field type, for reference
3367 * types this is a MonoObject*, for value types its the actual pointer to
3372 * mono_field_static_get_value (vt, int_field, &i);
3375 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3377 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3381 * mono_property_set_value:
3382 * @prop: MonoProperty to set
3383 * @obj: instance object on which to act
3384 * @params: parameters to pass to the propery
3385 * @exc: optional exception
3387 * Invokes the property's set method with the given arguments on the
3388 * object instance obj (or NULL for static properties).
3390 * You can pass NULL as the exc argument if you don't want to
3391 * catch exceptions, otherwise, *exc will be set to the exception
3392 * thrown, if any. if an exception is thrown, you can't use the
3393 * MonoObject* result from the function.
3396 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3398 default_mono_runtime_invoke (prop->set, obj, params, exc);
3402 * mono_property_get_value:
3403 * @prop: MonoProperty to fetch
3404 * @obj: instance object on which to act
3405 * @params: parameters to pass to the propery
3406 * @exc: optional exception
3408 * Invokes the property's get method with the given arguments on the
3409 * object instance obj (or NULL for static properties).
3411 * You can pass NULL as the exc argument if you don't want to
3412 * catch exceptions, otherwise, *exc will be set to the exception
3413 * thrown, if any. if an exception is thrown, you can't use the
3414 * MonoObject* result from the function.
3416 * Returns: the value from invoking the get method on the property.
3419 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3421 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3425 * mono_nullable_init:
3426 * @buf: The nullable structure to initialize.
3427 * @value: the value to initialize from
3428 * @klass: the type for the object
3430 * Initialize the nullable structure pointed to by @buf from @value which
3431 * should be a boxed value type. The size of @buf should be able to hold
3432 * as much data as the @klass->instance_size (which is the number of bytes
3433 * that will be copies).
3435 * Since Nullables have variable structure, we can not define a C
3436 * structure for them.
3439 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3441 MonoClass *param_class = klass->cast_class;
3443 mono_class_setup_fields_locking (klass);
3444 g_assert (klass->fields_inited);
3446 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3447 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3449 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3451 if (param_class->has_references)
3452 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3454 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3456 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3461 * mono_nullable_box:
3462 * @buf: The buffer representing the data to be boxed
3463 * @klass: the type to box it as.
3465 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3469 mono_nullable_box (guint8 *buf, MonoClass *klass)
3471 MonoClass *param_class = klass->cast_class;
3473 mono_class_setup_fields_locking (klass);
3474 g_assert (klass->fields_inited);
3476 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3477 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3479 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3480 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3481 if (param_class->has_references)
3482 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3484 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3492 * mono_get_delegate_invoke:
3493 * @klass: The delegate class
3495 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3498 mono_get_delegate_invoke (MonoClass *klass)
3502 /* This is called at runtime, so avoid the slower search in metadata */
3503 mono_class_setup_methods (klass);
3504 if (klass->exception_type)
3506 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3511 * mono_get_delegate_begin_invoke:
3512 * @klass: The delegate class
3514 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3517 mono_get_delegate_begin_invoke (MonoClass *klass)
3521 /* This is called at runtime, so avoid the slower search in metadata */
3522 mono_class_setup_methods (klass);
3523 if (klass->exception_type)
3525 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3530 * mono_get_delegate_end_invoke:
3531 * @klass: The delegate class
3533 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3536 mono_get_delegate_end_invoke (MonoClass *klass)
3540 /* This is called at runtime, so avoid the slower search in metadata */
3541 mono_class_setup_methods (klass);
3542 if (klass->exception_type)
3544 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3549 * mono_runtime_delegate_invoke:
3550 * @delegate: pointer to a delegate object.
3551 * @params: parameters for the delegate.
3552 * @exc: Pointer to the exception result.
3554 * Invokes the delegate method @delegate with the parameters provided.
3556 * You can pass NULL as the exc argument if you don't want to
3557 * catch exceptions, otherwise, *exc will be set to the exception
3558 * thrown, if any. if an exception is thrown, you can't use the
3559 * MonoObject* result from the function.
3562 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3565 MonoClass *klass = delegate->vtable->klass;
3567 im = mono_get_delegate_invoke (klass);
3569 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3571 return mono_runtime_invoke (im, delegate, params, exc);
3574 static char **main_args = NULL;
3575 static int num_main_args = 0;
3578 * mono_runtime_get_main_args:
3580 * Returns: a MonoArray with the arguments passed to the main program
3583 mono_runtime_get_main_args (void)
3587 MonoDomain *domain = mono_domain_get ();
3589 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3591 for (i = 0; i < num_main_args; ++i)
3592 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3598 free_main_args (void)
3602 for (i = 0; i < num_main_args; ++i)
3603 g_free (main_args [i]);
3610 * mono_runtime_set_main_args:
3611 * @argc: number of arguments from the command line
3612 * @argv: array of strings from the command line
3614 * Set the command line arguments from an embedding application that doesn't otherwise call
3615 * mono_runtime_run_main ().
3618 mono_runtime_set_main_args (int argc, char* argv[])
3623 main_args = g_new0 (char*, argc);
3624 num_main_args = argc;
3626 for (i = 0; i < argc; ++i) {
3629 utf8_arg = mono_utf8_from_external (argv[i]);
3630 if (utf8_arg == NULL) {
3631 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3632 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3636 main_args [i] = utf8_arg;
3643 * mono_runtime_run_main:
3644 * @method: the method to start the application with (usually Main)
3645 * @argc: number of arguments from the command line
3646 * @argv: array of strings from the command line
3647 * @exc: excetption results
3649 * Execute a standard Main() method (argc/argv contains the
3650 * executable name). This method also sets the command line argument value
3651 * needed by System.Environment.
3656 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3660 MonoArray *args = NULL;
3661 MonoDomain *domain = mono_domain_get ();
3662 gchar *utf8_fullpath;
3663 MonoMethodSignature *sig;
3665 g_assert (method != NULL);
3667 mono_thread_set_main (mono_thread_current ());
3669 main_args = g_new0 (char*, argc);
3670 num_main_args = argc;
3672 if (!g_path_is_absolute (argv [0])) {
3673 gchar *basename = g_path_get_basename (argv [0]);
3674 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3678 utf8_fullpath = mono_utf8_from_external (fullpath);
3679 if(utf8_fullpath == NULL) {
3680 /* Printing the arg text will cause glib to
3681 * whinge about "Invalid UTF-8", but at least
3682 * its relevant, and shows the problem text
3685 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3686 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3693 utf8_fullpath = mono_utf8_from_external (argv[0]);
3694 if(utf8_fullpath == NULL) {
3695 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3696 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3701 main_args [0] = utf8_fullpath;
3703 for (i = 1; i < argc; ++i) {
3706 utf8_arg=mono_utf8_from_external (argv[i]);
3707 if(utf8_arg==NULL) {
3708 /* Ditto the comment about Invalid UTF-8 here */
3709 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3710 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3714 main_args [i] = utf8_arg;
3719 sig = mono_method_signature (method);
3721 g_print ("Unable to load Main method.\n");
3725 if (sig->param_count) {
3726 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3727 for (i = 0; i < argc; ++i) {
3728 /* The encodings should all work, given that
3729 * we've checked all these args for the
3732 gchar *str = mono_utf8_from_external (argv [i]);
3733 MonoString *arg = mono_string_new (domain, str);
3734 mono_array_setref (args, i, arg);
3738 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3741 mono_assembly_set_main (method->klass->image->assembly);
3743 return mono_runtime_exec_main (method, args, exc);
3747 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3749 static MonoMethod *serialize_method;
3754 if (!serialize_method) {
3755 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3756 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3759 if (!serialize_method) {
3764 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3768 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3776 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3778 static MonoMethod *deserialize_method;
3783 if (!deserialize_method) {
3784 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3785 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3787 if (!deserialize_method) {
3794 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3801 #ifndef DISABLE_REMOTING
3803 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3805 static MonoMethod *get_proxy_method;
3807 MonoDomain *domain = mono_domain_get ();
3808 MonoRealProxy *real_proxy;
3809 MonoReflectionType *reflection_type;
3810 MonoTransparentProxy *transparent_proxy;
3812 if (!get_proxy_method)
3813 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3815 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3817 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3818 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3820 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3821 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3824 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3828 return (MonoObject*) transparent_proxy;
3830 #endif /* DISABLE_REMOTING */
3833 * mono_object_xdomain_representation
3835 * @target_domain: a domain
3836 * @exc: pointer to a MonoObject*
3838 * Creates a representation of obj in the domain target_domain. This
3839 * is either a copy of obj arrived through via serialization and
3840 * deserialization or a proxy, depending on whether the object is
3841 * serializable or marshal by ref. obj must not be in target_domain.
3843 * If the object cannot be represented in target_domain, NULL is
3844 * returned and *exc is set to an appropriate exception.
3847 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3849 MonoObject *deserialized = NULL;
3850 gboolean failure = FALSE;
3854 #ifndef DISABLE_REMOTING
3855 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3856 deserialized = make_transparent_proxy (obj, &failure, exc);
3861 MonoDomain *domain = mono_domain_get ();
3862 MonoObject *serialized;
3864 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3865 serialized = serialize_object (obj, &failure, exc);
3866 mono_domain_set_internal_with_options (target_domain, FALSE);
3868 deserialized = deserialize_object (serialized, &failure, exc);
3869 if (domain != target_domain)
3870 mono_domain_set_internal_with_options (domain, FALSE);
3873 return deserialized;
3876 /* Used in call_unhandled_exception_delegate */
3878 create_unhandled_exception_eventargs (MonoObject *exc)
3882 MonoMethod *method = NULL;
3883 MonoBoolean is_terminating = TRUE;
3886 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3889 mono_class_init (klass);
3891 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3892 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3896 args [1] = &is_terminating;
3898 obj = mono_object_new (mono_domain_get (), klass);
3899 mono_runtime_invoke (method, obj, args, NULL);
3904 /* Used in mono_unhandled_exception */
3906 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3907 MonoObject *e = NULL;
3909 MonoDomain *current_domain = mono_domain_get ();
3911 if (domain != current_domain)
3912 mono_domain_set_internal_with_options (domain, FALSE);
3914 g_assert (domain == mono_object_domain (domain->domain));
3916 if (mono_object_domain (exc) != domain) {
3917 MonoObject *serialization_exc;
3919 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3921 if (serialization_exc) {
3923 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3926 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3927 "System.Runtime.Serialization", "SerializationException",
3928 "Could not serialize unhandled exception.");
3932 g_assert (mono_object_domain (exc) == domain);
3934 pa [0] = domain->domain;
3935 pa [1] = create_unhandled_exception_eventargs (exc);
3936 mono_runtime_delegate_invoke (delegate, pa, &e);
3938 if (domain != current_domain)
3939 mono_domain_set_internal_with_options (current_domain, FALSE);
3943 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3944 if (!mono_error_ok (&error)) {
3945 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3946 mono_error_cleanup (&error);
3948 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3954 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3957 * mono_runtime_unhandled_exception_policy_set:
3958 * @policy: the new policy
3960 * This is a VM internal routine.
3962 * Sets the runtime policy for handling unhandled exceptions.
3965 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3966 runtime_unhandled_exception_policy = policy;
3970 * mono_runtime_unhandled_exception_policy_get:
3972 * This is a VM internal routine.
3974 * Gets the runtime policy for handling unhandled exceptions.
3976 MonoRuntimeUnhandledExceptionPolicy
3977 mono_runtime_unhandled_exception_policy_get (void) {
3978 return runtime_unhandled_exception_policy;
3982 * mono_unhandled_exception:
3983 * @exc: exception thrown
3985 * This is a VM internal routine.
3987 * We call this function when we detect an unhandled exception
3988 * in the default domain.
3990 * It invokes the * UnhandledException event in AppDomain or prints
3991 * a warning to the console
3994 mono_unhandled_exception (MonoObject *exc)
3996 MonoDomain *current_domain = mono_domain_get ();
3997 MonoDomain *root_domain = mono_get_root_domain ();
3998 MonoClassField *field;
3999 MonoObject *current_appdomain_delegate;
4000 MonoObject *root_appdomain_delegate;
4002 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
4003 "UnhandledException");
4006 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4007 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4008 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4009 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4010 if (current_domain != root_domain) {
4011 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4013 current_appdomain_delegate = NULL;
4016 /* set exitcode only if we will abort the process */
4017 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4019 mono_environment_exitcode_set (1);
4020 mono_print_unhandled_exception (exc);
4022 if (root_appdomain_delegate) {
4023 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4025 if (current_appdomain_delegate) {
4026 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4033 * mono_runtime_exec_managed_code:
4034 * @domain: Application domain
4035 * @main_func: function to invoke from the execution thread
4036 * @main_args: parameter to the main_func
4038 * Launch a new thread to execute a function
4040 * main_func is called back from the thread with main_args as the
4041 * parameter. The callback function is expected to start Main()
4042 * eventually. This function then waits for all managed threads to
4044 * It is not necesseray anymore to execute managed code in a subthread,
4045 * so this function should not be used anymore by default: just
4046 * execute the code and then call mono_thread_manage ().
4049 mono_runtime_exec_managed_code (MonoDomain *domain,
4050 MonoMainThreadFunc main_func,
4053 mono_thread_create (domain, main_func, main_args);
4055 mono_thread_manage ();
4059 * Execute a standard Main() method (args doesn't contain the
4063 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4068 MonoCustomAttrInfo* cinfo;
4069 gboolean has_stathread_attribute;
4070 MonoInternalThread* thread = mono_thread_internal_current ();
4076 domain = mono_object_domain (args);
4077 if (!domain->entry_assembly) {
4079 MonoAssembly *assembly;
4081 assembly = method->klass->image->assembly;
4082 domain->entry_assembly = assembly;
4083 /* Domains created from another domain already have application_base and configuration_file set */
4084 if (domain->setup->application_base == NULL) {
4085 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4088 if (domain->setup->configuration_file == NULL) {
4089 str = g_strconcat (assembly->image->name, ".config", NULL);
4090 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4092 mono_set_private_bin_path_from_config (domain);
4096 cinfo = mono_custom_attrs_from_method (method);
4098 static MonoClass *stathread_attribute = NULL;
4099 if (!stathread_attribute)
4100 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4101 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4103 mono_custom_attrs_free (cinfo);
4105 has_stathread_attribute = FALSE;
4107 if (has_stathread_attribute) {
4108 thread->apartment_state = ThreadApartmentState_STA;
4110 thread->apartment_state = ThreadApartmentState_MTA;
4112 mono_thread_init_apartment_state ();
4114 /* FIXME: check signature of method */
4115 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4117 res = mono_runtime_invoke (method, NULL, pa, exc);
4119 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4123 mono_environment_exitcode_set (rval);
4125 mono_runtime_invoke (method, NULL, pa, exc);
4129 /* If the return type of Main is void, only
4130 * set the exitcode if an exception was thrown
4131 * (we don't want to blow away an
4132 * explicitly-set exit code)
4135 mono_environment_exitcode_set (rval);
4143 * mono_install_runtime_invoke:
4144 * @func: Function to install
4146 * This is a VM internal routine
4149 mono_install_runtime_invoke (MonoInvokeFunc func)
4151 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4156 * mono_runtime_invoke_array:
4157 * @method: method to invoke
4158 * @obJ: object instance
4159 * @params: arguments to the method
4160 * @exc: exception information.
4162 * Invokes the method represented by @method on the object @obj.
4164 * obj is the 'this' pointer, it should be NULL for static
4165 * methods, a MonoObject* for object instances and a pointer to
4166 * the value type for value types.
4168 * The params array contains the arguments to the method with the
4169 * same convention: MonoObject* pointers for object instances and
4170 * pointers to the value type otherwise. The _invoke_array
4171 * variant takes a C# object[] as the params argument (MonoArray
4172 * *params): in this case the value types are boxed inside the
4173 * respective reference representation.
4175 * From unmanaged code you'll usually use the
4176 * mono_runtime_invoke() variant.
4178 * Note that this function doesn't handle virtual methods for
4179 * you, it will exec the exact method you pass: we still need to
4180 * expose a function to lookup the derived class implementation
4181 * of a virtual method (there are examples of this in the code,
4184 * You can pass NULL as the exc argument if you don't want to
4185 * catch exceptions, otherwise, *exc will be set to the exception
4186 * thrown, if any. if an exception is thrown, you can't use the
4187 * MonoObject* result from the function.
4189 * If the method returns a value type, it is boxed in an object
4193 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4196 MonoMethodSignature *sig = mono_method_signature (method);
4197 gpointer *pa = NULL;
4200 gboolean has_byref_nullables = FALSE;
4202 if (NULL != params) {
4203 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4204 for (i = 0; i < mono_array_length (params); i++) {
4205 MonoType *t = sig->params [i];
4211 case MONO_TYPE_BOOLEAN:
4214 case MONO_TYPE_CHAR:
4223 case MONO_TYPE_VALUETYPE:
4224 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4225 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4226 pa [i] = mono_array_get (params, MonoObject*, i);
4228 has_byref_nullables = TRUE;
4230 /* MS seems to create the objects if a null is passed in */
4231 if (!mono_array_get (params, MonoObject*, i))
4232 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4236 * We can't pass the unboxed vtype byref to the callee, since
4237 * that would mean the callee would be able to modify boxed
4238 * primitive types. So we (and MS) make a copy of the boxed
4239 * object, pass that to the callee, and replace the original
4240 * boxed object in the arg array with the copy.
4242 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4243 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4244 mono_array_setref (params, i, copy);
4247 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4250 case MONO_TYPE_STRING:
4251 case MONO_TYPE_OBJECT:
4252 case MONO_TYPE_CLASS:
4253 case MONO_TYPE_ARRAY:
4254 case MONO_TYPE_SZARRAY:
4256 pa [i] = mono_array_addr (params, MonoObject*, i);
4257 // FIXME: I need to check this code path
4259 pa [i] = mono_array_get (params, MonoObject*, i);
4261 case MONO_TYPE_GENERICINST:
4263 t = &t->data.generic_class->container_class->this_arg;
4265 t = &t->data.generic_class->container_class->byval_arg;
4267 case MONO_TYPE_PTR: {
4270 /* The argument should be an IntPtr */
4271 arg = mono_array_get (params, MonoObject*, i);
4275 g_assert (arg->vtable->klass == mono_defaults.int_class);
4276 pa [i] = ((MonoIntPtr*)arg)->m_value;
4281 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4286 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4289 if (mono_class_is_nullable (method->klass)) {
4290 /* Need to create a boxed vtype instead */
4296 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4300 obj = mono_object_new (mono_domain_get (), method->klass);
4301 g_assert (obj); /*maybe we should raise a TLE instead?*/
4302 #ifndef DISABLE_REMOTING
4303 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4304 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4307 if (method->klass->valuetype)
4308 o = mono_object_unbox (obj);
4311 } else if (method->klass->valuetype) {
4312 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4315 mono_runtime_invoke (method, o, pa, exc);
4318 if (mono_class_is_nullable (method->klass)) {
4319 MonoObject *nullable;
4321 /* Convert the unboxed vtype into a Nullable structure */
4322 nullable = mono_object_new (mono_domain_get (), method->klass);
4324 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4325 obj = mono_object_unbox (nullable);
4328 /* obj must be already unboxed if needed */
4329 res = mono_runtime_invoke (method, obj, pa, exc);
4331 if (sig->ret->type == MONO_TYPE_PTR) {
4332 MonoClass *pointer_class;
4333 static MonoMethod *box_method;
4335 MonoObject *box_exc;
4338 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4339 * convert it to a Pointer object.
4341 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4343 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4345 g_assert (res->vtable->klass == mono_defaults.int_class);
4346 box_args [0] = ((MonoIntPtr*)res)->m_value;
4347 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4348 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4349 g_assert (!box_exc);
4352 if (has_byref_nullables) {
4354 * The runtime invoke wrapper already converted byref nullables back,
4355 * and stored them in pa, we just need to copy them back to the
4358 for (i = 0; i < mono_array_length (params); i++) {
4359 MonoType *t = sig->params [i];
4361 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4362 mono_array_setref (params, i, pa [i]);
4371 arith_overflow (void)
4373 mono_raise_exception (mono_get_exception_overflow ());
4377 * mono_object_allocate:
4378 * @size: number of bytes to allocate
4380 * This is a very simplistic routine until we have our GC-aware
4383 * Returns: an allocated object of size @size, or NULL on failure.
4385 static inline void *
4386 mono_object_allocate (size_t size, MonoVTable *vtable)
4389 ALLOC_OBJECT (o, vtable, size);
4394 #ifndef HAVE_SGEN_GC
4396 * mono_object_allocate_ptrfree:
4397 * @size: number of bytes to allocate
4399 * Note that the memory allocated is not zeroed.
4400 * Returns: an allocated object of size @size, or NULL on failure.
4402 static inline void *
4403 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4406 ALLOC_PTRFREE (o, vtable, size);
4411 static inline void *
4412 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4415 ALLOC_TYPED (o, size, vtable);
4422 * @klass: the class of the object that we want to create
4424 * Returns: a newly created object whose definition is
4425 * looked up using @klass. This will not invoke any constructors,
4426 * so the consumer of this routine has to invoke any constructors on
4427 * its own to initialize the object.
4429 * It returns NULL on failure.
4432 mono_object_new (MonoDomain *domain, MonoClass *klass)
4436 vtable = mono_class_vtable (domain, klass);
4439 return mono_object_new_specific (vtable);
4443 * mono_object_new_pinned:
4445 * Same as mono_object_new, but the returned object will be pinned.
4446 * For SGEN, these objects will only be freed at appdomain unload.
4449 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4453 vtable = mono_class_vtable (domain, klass);
4458 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4460 return mono_object_new_specific (vtable);
4465 * mono_object_new_specific:
4466 * @vtable: the vtable of the object that we want to create
4468 * Returns: A newly created object with class and domain specified
4472 mono_object_new_specific (MonoVTable *vtable)
4476 /* check for is_com_object for COM Interop */
4477 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4480 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4483 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4486 mono_class_init (klass);
4488 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4490 vtable->domain->create_proxy_for_type_method = im;
4493 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4495 o = mono_runtime_invoke (im, NULL, pa, NULL);
4496 if (o != NULL) return o;
4499 return mono_object_new_alloc_specific (vtable);
4503 mono_object_new_alloc_specific (MonoVTable *vtable)
4507 if (!vtable->klass->has_references) {
4508 o = mono_object_new_ptrfree (vtable);
4509 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4510 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4512 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4513 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4515 if (G_UNLIKELY (vtable->klass->has_finalize))
4516 mono_object_register_finalizer (o);
4518 if (G_UNLIKELY (profile_allocs))
4519 mono_profiler_allocation (o, vtable->klass);
4524 mono_object_new_fast (MonoVTable *vtable)
4527 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4532 mono_object_new_ptrfree (MonoVTable *vtable)
4535 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4536 #if NEED_TO_ZERO_PTRFREE
4537 /* an inline memset is much faster for the common vcase of small objects
4538 * note we assume the allocated size is a multiple of sizeof (void*).
4540 if (vtable->klass->instance_size < 128) {
4542 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4543 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4549 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4556 mono_object_new_ptrfree_box (MonoVTable *vtable)
4559 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4560 /* the object will be boxed right away, no need to memzero it */
4565 * mono_class_get_allocation_ftn:
4567 * @for_box: the object will be used for boxing
4568 * @pass_size_in_words:
4570 * Return the allocation function appropriate for the given class.
4574 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4576 *pass_size_in_words = FALSE;
4578 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4579 profile_allocs = FALSE;
4581 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4582 return mono_object_new_specific;
4584 if (!vtable->klass->has_references) {
4585 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4587 return mono_object_new_ptrfree_box;
4588 return mono_object_new_ptrfree;
4591 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4593 return mono_object_new_fast;
4596 * FIXME: This is actually slower than mono_object_new_fast, because
4597 * of the overhead of parameter passing.
4600 *pass_size_in_words = TRUE;
4601 #ifdef GC_REDIRECT_TO_LOCAL
4602 return GC_local_gcj_fast_malloc;
4604 return GC_gcj_fast_malloc;
4609 return mono_object_new_specific;
4613 * mono_object_new_from_token:
4614 * @image: Context where the type_token is hosted
4615 * @token: a token of the type that we want to create
4617 * Returns: A newly created object whose definition is
4618 * looked up using @token in the @image image
4621 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4626 class = mono_class_get_checked (image, token, &error);
4627 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4629 return mono_object_new (domain, class);
4634 * mono_object_clone:
4635 * @obj: the object to clone
4637 * Returns: A newly created object who is a shallow copy of @obj
4640 mono_object_clone (MonoObject *obj)
4643 int size = obj->vtable->klass->instance_size;
4645 if (obj->vtable->klass->rank)
4646 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4648 o = mono_object_allocate (size, obj->vtable);
4650 if (obj->vtable->klass->has_references) {
4651 mono_gc_wbarrier_object_copy (o, obj);
4653 int size = obj->vtable->klass->instance_size;
4654 /* do not copy the sync state */
4655 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4657 if (G_UNLIKELY (profile_allocs))
4658 mono_profiler_allocation (o, obj->vtable->klass);
4660 if (obj->vtable->klass->has_finalize)
4661 mono_object_register_finalizer (o);
4666 * mono_array_full_copy:
4667 * @src: source array to copy
4668 * @dest: destination array
4670 * Copies the content of one array to another with exactly the same type and size.
4673 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4676 MonoClass *klass = src->obj.vtable->klass;
4678 g_assert (klass == dest->obj.vtable->klass);
4680 size = mono_array_length (src);
4681 g_assert (size == mono_array_length (dest));
4682 size *= mono_array_element_size (klass);
4684 if (klass->element_class->valuetype) {
4685 if (klass->element_class->has_references)
4686 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4688 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4690 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4693 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4698 * mono_array_clone_in_domain:
4699 * @domain: the domain in which the array will be cloned into
4700 * @array: the array to clone
4702 * This routine returns a copy of the array that is hosted on the
4703 * specified MonoDomain.
4706 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4711 MonoClass *klass = array->obj.vtable->klass;
4713 if (array->bounds == NULL) {
4714 size = mono_array_length (array);
4715 o = mono_array_new_full (domain, klass, &size, NULL);
4717 size *= mono_array_element_size (klass);
4719 if (klass->element_class->valuetype) {
4720 if (klass->element_class->has_references)
4721 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4723 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4725 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4728 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4733 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4734 size = mono_array_element_size (klass);
4735 for (i = 0; i < klass->rank; ++i) {
4736 sizes [i] = array->bounds [i].length;
4737 size *= array->bounds [i].length;
4738 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4740 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4742 if (klass->element_class->valuetype) {
4743 if (klass->element_class->has_references)
4744 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4746 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4748 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4751 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4759 * @array: the array to clone
4761 * Returns: A newly created array who is a shallow copy of @array
4764 mono_array_clone (MonoArray *array)
4766 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4769 /* helper macros to check for overflow when calculating the size of arrays */
4770 #ifdef MONO_BIG_ARRAYS
4771 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4772 #define MYGUINT_MAX MYGUINT64_MAX
4773 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4774 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4775 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4776 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4777 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4779 #define MYGUINT32_MAX 4294967295U
4780 #define MYGUINT_MAX MYGUINT32_MAX
4781 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4782 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4783 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4784 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4785 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4789 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4793 byte_len = mono_array_element_size (class);
4794 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4797 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4799 byte_len += sizeof (MonoArray);
4807 * mono_array_new_full:
4808 * @domain: domain where the object is created
4809 * @array_class: array class
4810 * @lengths: lengths for each dimension in the array
4811 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4813 * This routine creates a new array objects with the given dimensions,
4814 * lower bounds and type.
4817 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4819 uintptr_t byte_len = 0, len, bounds_size;
4822 MonoArrayBounds *bounds;
4826 if (!array_class->inited)
4827 mono_class_init (array_class);
4831 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4832 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4834 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4838 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4840 for (i = 0; i < array_class->rank; ++i) {
4841 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4843 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4844 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4849 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4850 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4854 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4855 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4856 byte_len = (byte_len + 3) & ~3;
4857 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4858 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4859 byte_len += bounds_size;
4862 * Following three lines almost taken from mono_object_new ():
4863 * they need to be kept in sync.
4865 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4866 #ifndef HAVE_SGEN_GC
4867 if (!array_class->has_references) {
4868 o = mono_object_allocate_ptrfree (byte_len, vtable);
4869 #if NEED_TO_ZERO_PTRFREE
4870 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4872 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4873 o = mono_object_allocate_spec (byte_len, vtable);
4875 o = mono_object_allocate (byte_len, vtable);
4878 array = (MonoArray*)o;
4879 array->max_length = len;
4882 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4883 array->bounds = bounds;
4887 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4889 o = mono_gc_alloc_vector (vtable, byte_len, len);
4890 array = (MonoArray*)o;
4892 bounds = array->bounds;
4896 for (i = 0; i < array_class->rank; ++i) {
4897 bounds [i].length = lengths [i];
4899 bounds [i].lower_bound = lower_bounds [i];
4903 if (G_UNLIKELY (profile_allocs))
4904 mono_profiler_allocation (o, array_class);
4911 * @domain: domain where the object is created
4912 * @eclass: element class
4913 * @n: number of array elements
4915 * This routine creates a new szarray with @n elements of type @eclass.
4918 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4922 ac = mono_array_class_get (eclass, 1);
4925 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4929 * mono_array_new_specific:
4930 * @vtable: a vtable in the appropriate domain for an initialized class
4931 * @n: number of array elements
4933 * This routine is a fast alternative to mono_array_new() for code which
4934 * can be sure about the domain it operates in.
4937 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4943 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4948 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4949 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4952 #ifndef HAVE_SGEN_GC
4953 if (!vtable->klass->has_references) {
4954 o = mono_object_allocate_ptrfree (byte_len, vtable);
4955 #if NEED_TO_ZERO_PTRFREE
4956 ((MonoArray*)o)->bounds = NULL;
4957 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4959 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4960 o = mono_object_allocate_spec (byte_len, vtable);
4962 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4963 o = mono_object_allocate (byte_len, vtable);
4966 ao = (MonoArray *)o;
4969 o = mono_gc_alloc_vector (vtable, byte_len, n);
4973 if (G_UNLIKELY (profile_allocs))
4974 mono_profiler_allocation (o, vtable->klass);
4980 * mono_string_new_utf16:
4981 * @text: a pointer to an utf16 string
4982 * @len: the length of the string
4984 * Returns: A newly created string object which contains @text.
4987 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4991 s = mono_string_new_size (domain, len);
4992 g_assert (s != NULL);
4994 memcpy (mono_string_chars (s), text, len * 2);
5000 * mono_string_new_utf32:
5001 * @text: a pointer to an utf32 string
5002 * @len: the length of the string
5004 * Returns: A newly created string object which contains @text.
5007 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5010 mono_unichar2 *utf16_output = NULL;
5011 gint32 utf16_len = 0;
5012 GError *error = NULL;
5013 glong items_written;
5015 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5018 g_error_free (error);
5020 while (utf16_output [utf16_len]) utf16_len++;
5022 s = mono_string_new_size (domain, utf16_len);
5023 g_assert (s != NULL);
5025 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5027 g_free (utf16_output);
5033 * mono_string_new_size:
5034 * @text: a pointer to an utf16 string
5035 * @len: the length of the string
5037 * Returns: A newly created string object of @len
5040 mono_string_new_size (MonoDomain *domain, gint32 len)
5046 /* check for overflow */
5047 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 2) / 2))
5048 mono_gc_out_of_memory (-1);
5050 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5051 g_assert (size > 0);
5053 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5056 #ifndef HAVE_SGEN_GC
5057 s = mono_object_allocate_ptrfree (size, vtable);
5061 s = mono_gc_alloc_string (vtable, size, len);
5063 #if NEED_TO_ZERO_PTRFREE
5066 if (G_UNLIKELY (profile_allocs))
5067 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5073 * mono_string_new_len:
5074 * @text: a pointer to an utf8 string
5075 * @length: number of bytes in @text to consider
5077 * Returns: A newly created string object which contains @text.
5080 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5082 GError *error = NULL;
5083 MonoString *o = NULL;
5085 glong items_written;
5087 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5090 o = mono_string_new_utf16 (domain, ut, items_written);
5092 g_error_free (error);
5101 * @text: a pointer to an utf8 string
5103 * Returns: A newly created string object which contains @text.
5106 mono_string_new (MonoDomain *domain, const char *text)
5108 GError *error = NULL;
5109 MonoString *o = NULL;
5111 glong items_written;
5116 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5119 o = mono_string_new_utf16 (domain, ut, items_written);
5121 g_error_free (error);
5124 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5129 MonoString *o = NULL;
5131 if (!g_utf8_validate (text, -1, &end))
5134 len = g_utf8_strlen (text, -1);
5135 o = mono_string_new_size (domain, len);
5136 str = mono_string_chars (o);
5138 while (text < end) {
5139 *str++ = g_utf8_get_char (text);
5140 text = g_utf8_next_char (text);
5147 * mono_string_new_wrapper:
5148 * @text: pointer to utf8 characters.
5150 * Helper function to create a string object from @text in the current domain.
5153 mono_string_new_wrapper (const char *text)
5155 MonoDomain *domain = mono_domain_get ();
5158 return mono_string_new (domain, text);
5165 * @class: the class of the value
5166 * @value: a pointer to the unboxed data
5168 * Returns: A newly created object which contains @value.
5171 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5177 g_assert (class->valuetype);
5178 if (mono_class_is_nullable (class))
5179 return mono_nullable_box (value, class);
5181 vtable = mono_class_vtable (domain, class);
5184 size = mono_class_instance_size (class);
5185 res = mono_object_new_alloc_specific (vtable);
5186 if (G_UNLIKELY (profile_allocs))
5187 mono_profiler_allocation (res, class);
5189 size = size - sizeof (MonoObject);
5192 g_assert (size == mono_class_value_size (class, NULL));
5193 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5195 #if NO_UNALIGNED_ACCESS
5196 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5200 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5203 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5206 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5209 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5212 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5216 if (class->has_finalize)
5217 mono_object_register_finalizer (res);
5223 * @dest: destination pointer
5224 * @src: source pointer
5225 * @klass: a valuetype class
5227 * Copy a valuetype from @src to @dest. This function must be used
5228 * when @klass contains references fields.
5231 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5233 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5237 * mono_value_copy_array:
5238 * @dest: destination array
5239 * @dest_idx: index in the @dest array
5240 * @src: source pointer
5241 * @count: number of items
5243 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5244 * This function must be used when @klass contains references fields.
5245 * Overlap is handled.
5248 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5250 int size = mono_array_element_size (dest->obj.vtable->klass);
5251 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5252 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5253 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5257 * mono_object_get_domain:
5258 * @obj: object to query
5260 * Returns: the MonoDomain where the object is hosted
5263 mono_object_get_domain (MonoObject *obj)
5265 return mono_object_domain (obj);
5269 * mono_object_get_class:
5270 * @obj: object to query
5272 * Returns: the MonOClass of the object.
5275 mono_object_get_class (MonoObject *obj)
5277 return mono_object_class (obj);
5280 * mono_object_get_size:
5281 * @o: object to query
5283 * Returns: the size, in bytes, of @o
5286 mono_object_get_size (MonoObject* o)
5288 MonoClass* klass = mono_object_class (o);
5289 if (klass == mono_defaults.string_class) {
5290 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5291 } else if (o->vtable->rank) {
5292 MonoArray *array = (MonoArray*)o;
5293 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5294 if (array->bounds) {
5297 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5301 return mono_class_instance_size (klass);
5306 * mono_object_unbox:
5307 * @obj: object to unbox
5309 * Returns: a pointer to the start of the valuetype boxed in this
5312 * This method will assert if the object passed is not a valuetype.
5315 mono_object_unbox (MonoObject *obj)
5317 /* add assert for valuetypes? */
5318 g_assert (obj->vtable->klass->valuetype);
5319 return ((char*)obj) + sizeof (MonoObject);
5323 * mono_object_isinst:
5325 * @klass: a pointer to a class
5327 * Returns: @obj if @obj is derived from @klass
5330 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5333 mono_class_init (klass);
5335 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5336 return mono_object_isinst_mbyref (obj, klass);
5341 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5345 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5354 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5355 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5359 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5360 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5363 MonoClass *oklass = vt->klass;
5364 if (mono_class_is_transparent_proxy (oklass))
5365 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5367 mono_class_setup_supertypes (klass);
5368 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5371 #ifndef DISABLE_REMOTING
5372 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5374 MonoDomain *domain = mono_domain_get ();
5376 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5377 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5378 MonoMethod *im = NULL;
5381 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5382 im = mono_object_get_virtual_method (rp, im);
5385 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5388 res = mono_runtime_invoke (im, rp, pa, NULL);
5390 if (*(MonoBoolean *) mono_object_unbox(res)) {
5391 /* Update the vtable of the remote type, so it can safely cast to this new type */
5392 mono_upgrade_remote_class (domain, obj, klass);
5396 #endif /* DISABLE_REMOTING */
5401 * mono_object_castclass_mbyref:
5403 * @klass: a pointer to a class
5405 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5408 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5410 if (!obj) return NULL;
5411 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5413 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5415 "InvalidCastException"));
5420 MonoDomain *orig_domain;
5426 str_lookup (MonoDomain *domain, gpointer user_data)
5428 LDStrInfo *info = user_data;
5429 if (info->res || domain == info->orig_domain)
5431 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5437 mono_string_get_pinned (MonoString *str)
5441 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5442 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5444 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5445 news->length = mono_string_length (str);
5451 #define mono_string_get_pinned(str) (str)
5455 mono_string_is_interned_lookup (MonoString *str, int insert)
5457 MonoGHashTable *ldstr_table;
5458 MonoString *s, *res;
5461 domain = ((MonoObject *)str)->vtable->domain;
5462 ldstr_table = domain->ldstr_table;
5464 res = mono_g_hash_table_lookup (ldstr_table, str);
5470 /* Allocate outside the lock */
5472 s = mono_string_get_pinned (str);
5475 res = mono_g_hash_table_lookup (ldstr_table, str);
5480 mono_g_hash_table_insert (ldstr_table, s, s);
5485 LDStrInfo ldstr_info;
5486 ldstr_info.orig_domain = domain;
5487 ldstr_info.ins = str;
5488 ldstr_info.res = NULL;
5490 mono_domain_foreach (str_lookup, &ldstr_info);
5491 if (ldstr_info.res) {
5493 * the string was already interned in some other domain:
5494 * intern it in the current one as well.
5496 mono_g_hash_table_insert (ldstr_table, str, str);
5506 * mono_string_is_interned:
5507 * @o: String to probe
5509 * Returns whether the string has been interned.
5512 mono_string_is_interned (MonoString *o)
5514 return mono_string_is_interned_lookup (o, FALSE);
5518 * mono_string_intern:
5519 * @o: String to intern
5521 * Interns the string passed.
5522 * Returns: The interned string.
5525 mono_string_intern (MonoString *str)
5527 return mono_string_is_interned_lookup (str, TRUE);
5532 * @domain: the domain where the string will be used.
5533 * @image: a metadata context
5534 * @idx: index into the user string table.
5536 * Implementation for the ldstr opcode.
5537 * Returns: a loaded string from the @image/@idx combination.
5540 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5542 if (image->dynamic) {
5543 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5546 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5547 return NULL; /*FIXME we should probably be raising an exception here*/
5548 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5553 * mono_ldstr_metadata_sig
5554 * @domain: the domain for the string
5555 * @sig: the signature of a metadata string
5557 * Returns: a MonoString for a string stored in the metadata
5560 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5562 const char *str = sig;
5563 MonoString *o, *interned;
5566 len2 = mono_metadata_decode_blob_size (str, &str);
5569 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5570 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5573 guint16 *p2 = (guint16*)mono_string_chars (o);
5574 for (i = 0; i < len2; ++i) {
5575 *p2 = GUINT16_FROM_LE (*p2);
5581 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5583 /* o will get garbage collected */
5587 o = mono_string_get_pinned (o);
5589 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5596 * mono_string_to_utf8:
5597 * @s: a System.String
5599 * Returns the UTF8 representation for @s.
5600 * The resulting buffer needs to be freed with mono_free().
5602 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5605 mono_string_to_utf8 (MonoString *s)
5608 char *result = mono_string_to_utf8_checked (s, &error);
5610 if (!mono_error_ok (&error))
5611 mono_error_raise_exception (&error);
5616 * mono_string_to_utf8_checked:
5617 * @s: a System.String
5618 * @error: a MonoError.
5620 * Converts a MonoString to its UTF8 representation. May fail; check
5621 * @error to determine whether the conversion was successful.
5622 * The resulting buffer should be freed with mono_free().
5625 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5629 GError *gerror = NULL;
5631 mono_error_init (error);
5637 return g_strdup ("");
5639 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5641 mono_error_set_argument (error, "string", "%s", gerror->message);
5642 g_error_free (gerror);
5645 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5646 if (s->length > written) {
5647 /* allocate the total length and copy the part of the string that has been converted */
5648 char *as2 = g_malloc0 (s->length);
5649 memcpy (as2, as, written);
5658 * mono_string_to_utf8_ignore:
5661 * Converts a MonoString to its UTF8 representation. Will ignore
5662 * invalid surrogate pairs.
5663 * The resulting buffer should be freed with mono_free().
5667 mono_string_to_utf8_ignore (MonoString *s)
5676 return g_strdup ("");
5678 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5680 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5681 if (s->length > written) {
5682 /* allocate the total length and copy the part of the string that has been converted */
5683 char *as2 = g_malloc0 (s->length);
5684 memcpy (as2, as, written);
5693 * mono_string_to_utf8_image_ignore:
5694 * @s: a System.String
5696 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5699 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5701 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5705 * mono_string_to_utf8_mp_ignore:
5706 * @s: a System.String
5708 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5711 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5713 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5718 * mono_string_to_utf16:
5721 * Return an null-terminated array of the utf-16 chars
5722 * contained in @s. The result must be freed with g_free().
5723 * This is a temporary helper until our string implementation
5724 * is reworked to always include the null terminating char.
5727 mono_string_to_utf16 (MonoString *s)
5734 as = g_malloc ((s->length * 2) + 2);
5735 as [(s->length * 2)] = '\0';
5736 as [(s->length * 2) + 1] = '\0';
5739 return (gunichar2 *)(as);
5742 memcpy (as, mono_string_chars(s), s->length * 2);
5743 return (gunichar2 *)(as);
5747 * mono_string_to_utf32:
5750 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5751 * contained in @s. The result must be freed with g_free().
5754 mono_string_to_utf32 (MonoString *s)
5756 mono_unichar4 *utf32_output = NULL;
5757 GError *error = NULL;
5758 glong items_written;
5763 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5766 g_error_free (error);
5768 return utf32_output;
5772 * mono_string_from_utf16:
5773 * @data: the UTF16 string (LPWSTR) to convert
5775 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5777 * Returns: a MonoString.
5780 mono_string_from_utf16 (gunichar2 *data)
5782 MonoDomain *domain = mono_domain_get ();
5788 while (data [len]) len++;
5790 return mono_string_new_utf16 (domain, data, len);
5794 * mono_string_from_utf32:
5795 * @data: the UTF32 string (LPWSTR) to convert
5797 * Converts a UTF32 (UCS-4)to a MonoString.
5799 * Returns: a MonoString.
5802 mono_string_from_utf32 (mono_unichar4 *data)
5804 MonoString* result = NULL;
5805 mono_unichar2 *utf16_output = NULL;
5806 GError *error = NULL;
5807 glong items_written;
5813 while (data [len]) len++;
5815 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5818 g_error_free (error);
5820 result = mono_string_from_utf16 (utf16_output);
5821 g_free (utf16_output);
5826 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5833 r = mono_string_to_utf8_ignore (s);
5835 r = mono_string_to_utf8_checked (s, error);
5836 if (!mono_error_ok (error))
5843 len = strlen (r) + 1;
5845 mp_s = mono_mempool_alloc (mp, len);
5847 mp_s = mono_image_alloc (image, len);
5849 memcpy (mp_s, r, len);
5857 * mono_string_to_utf8_image:
5858 * @s: a System.String
5860 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5863 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5865 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5869 * mono_string_to_utf8_mp:
5870 * @s: a System.String
5872 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5875 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5877 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5881 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5884 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5886 eh_callbacks = *cbs;
5889 MonoRuntimeExceptionHandlingCallbacks *
5890 mono_get_eh_callbacks (void)
5892 return &eh_callbacks;
5896 * mono_raise_exception:
5897 * @ex: exception object
5899 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5902 mono_raise_exception (MonoException *ex)
5905 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5906 * that will cause gcc to omit the function epilog, causing problems when
5907 * the JIT tries to walk the stack, since the return address on the stack
5908 * will point into the next function in the executable, not this one.
5910 eh_callbacks.mono_raise_exception (ex);
5914 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5916 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5920 * mono_wait_handle_new:
5921 * @domain: Domain where the object will be created
5922 * @handle: Handle for the wait handle
5924 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5927 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5929 MonoWaitHandle *res;
5930 gpointer params [1];
5931 static MonoMethod *handle_set;
5933 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5935 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5937 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5939 params [0] = &handle;
5940 mono_runtime_invoke (handle_set, res, params, NULL);
5946 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5948 static MonoClassField *f_os_handle;
5949 static MonoClassField *f_safe_handle;
5951 if (!f_os_handle && !f_safe_handle) {
5952 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5953 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5958 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5962 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5969 mono_runtime_capture_context (MonoDomain *domain)
5971 RuntimeInvokeFunction runtime_invoke;
5973 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5974 MonoMethod *method = mono_get_context_capture_method ();
5975 MonoMethod *wrapper;
5978 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5979 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5980 domain->capture_context_method = mono_compile_method (method);
5983 runtime_invoke = domain->capture_context_runtime_invoke;
5985 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5988 * mono_async_result_new:
5989 * @domain:domain where the object will be created.
5990 * @handle: wait handle.
5991 * @state: state to pass to AsyncResult
5992 * @data: C closure data.
5994 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5995 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5999 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6001 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6002 MonoObject *context = mono_runtime_capture_context (domain);
6003 /* we must capture the execution context from the original thread */
6005 MONO_OBJECT_SETREF (res, execution_context, context);
6006 /* note: result may be null if the flow is suppressed */
6010 MONO_OBJECT_SETREF (res, object_data, object_data);
6011 MONO_OBJECT_SETREF (res, async_state, state);
6013 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6015 res->sync_completed = FALSE;
6016 res->completed = FALSE;
6022 mono_message_init (MonoDomain *domain,
6023 MonoMethodMessage *this,
6024 MonoReflectionMethod *method,
6025 MonoArray *out_args)
6027 static MonoClass *object_array_klass;
6028 static MonoClass *byte_array_klass;
6029 static MonoClass *string_array_klass;
6030 MonoMethodSignature *sig = mono_method_signature (method->method);
6036 if (!object_array_klass) {
6039 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6041 byte_array_klass = klass;
6043 klass = mono_array_class_get (mono_defaults.string_class, 1);
6045 string_array_klass = klass;
6047 klass = mono_array_class_get (mono_defaults.object_class, 1);
6050 mono_atomic_store_release (&object_array_klass, klass);
6053 MONO_OBJECT_SETREF (this, method, method);
6055 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6056 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6057 this->async_result = NULL;
6058 this->call_type = CallType_Sync;
6060 names = g_new (char *, sig->param_count);
6061 mono_method_get_param_names (method->method, (const char **) names);
6062 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6064 for (i = 0; i < sig->param_count; i++) {
6065 name = mono_string_new (domain, names [i]);
6066 mono_array_setref (this->names, i, name);
6070 for (i = 0, j = 0; i < sig->param_count; i++) {
6071 if (sig->params [i]->byref) {
6073 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6074 mono_array_setref (this->args, i, arg);
6078 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6082 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6085 mono_array_set (this->arg_types, guint8, i, arg_type);
6089 #ifndef DISABLE_REMOTING
6091 * mono_remoting_invoke:
6092 * @real_proxy: pointer to a RealProxy object
6093 * @msg: The MonoMethodMessage to execute
6094 * @exc: used to store exceptions
6095 * @out_args: used to store output arguments
6097 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6098 * IMessage interface and it is not trivial to extract results from there. So
6099 * we call an helper method PrivateInvoke instead of calling
6100 * RealProxy::Invoke() directly.
6102 * Returns: the result object.
6105 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6106 MonoObject **exc, MonoArray **out_args)
6108 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6111 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6114 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6116 real_proxy->vtable->domain->private_invoke_method = im;
6119 pa [0] = real_proxy;
6124 return mono_runtime_invoke (im, NULL, pa, exc);
6129 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6130 MonoObject **exc, MonoArray **out_args)
6132 static MonoClass *object_array_klass;
6135 MonoMethodSignature *sig;
6137 int i, j, outarg_count = 0;
6139 #ifndef DISABLE_REMOTING
6140 if (target && mono_object_is_transparent_proxy (target)) {
6141 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6142 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6143 target = tp->rp->unwrapped_server;
6145 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6150 domain = mono_domain_get ();
6151 method = msg->method->method;
6152 sig = mono_method_signature (method);
6154 for (i = 0; i < sig->param_count; i++) {
6155 if (sig->params [i]->byref)
6159 if (!object_array_klass) {
6162 klass = mono_array_class_get (mono_defaults.object_class, 1);
6165 mono_memory_barrier ();
6166 object_array_klass = klass;
6169 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6170 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6173 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6175 for (i = 0, j = 0; i < sig->param_count; i++) {
6176 if (sig->params [i]->byref) {
6178 arg = mono_array_get (msg->args, gpointer, i);
6179 mono_array_setref (*out_args, j, arg);
6188 * mono_object_to_string:
6190 * @exc: Any exception thrown by ToString (). May be NULL.
6192 * Returns: the result of calling ToString () on an object.
6195 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6197 static MonoMethod *to_string = NULL;
6204 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6206 method = mono_object_get_virtual_method (obj, to_string);
6208 // Unbox value type if needed
6209 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6210 target = mono_object_unbox (obj);
6213 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6217 * mono_print_unhandled_exception:
6218 * @exc: The exception
6220 * Prints the unhandled exception.
6223 mono_print_unhandled_exception (MonoObject *exc)
6226 char *message = (char*)"";
6227 gboolean free_message = FALSE;
6230 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6231 message = g_strdup ("OutOfMemoryException");
6232 free_message = TRUE;
6235 if (((MonoException*)exc)->native_trace_ips) {
6236 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6237 free_message = TRUE;
6239 MonoObject *other_exc = NULL;
6240 str = mono_object_to_string (exc, &other_exc);
6242 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6243 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6245 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6246 original_backtrace, nested_backtrace);
6248 g_free (original_backtrace);
6249 g_free (nested_backtrace);
6250 free_message = TRUE;
6252 message = mono_string_to_utf8_checked (str, &error);
6253 if (!mono_error_ok (&error)) {
6254 mono_error_cleanup (&error);
6255 message = (char *) "";
6257 free_message = TRUE;
6264 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6265 * exc->vtable->klass->name, message);
6267 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6274 * mono_delegate_ctor:
6275 * @this: pointer to an uninitialized delegate object
6276 * @target: target object
6277 * @addr: pointer to native code
6280 * Initialize a delegate and sets a specific method, not the one
6281 * associated with addr. This is useful when sharing generic code.
6282 * In that case addr will most probably not be associated with the
6283 * correct instantiation of the method.
6286 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6288 MonoDelegate *delegate = (MonoDelegate *)this;
6294 delegate->method = method;
6296 mono_stats.delegate_creations++;
6298 #ifndef DISABLE_REMOTING
6299 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6301 method = mono_marshal_get_remoting_invoke (method);
6302 delegate->method_ptr = mono_compile_method (method);
6303 MONO_OBJECT_SETREF (delegate, target, target);
6307 delegate->method_ptr = addr;
6308 MONO_OBJECT_SETREF (delegate, target, target);
6311 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6315 * mono_delegate_ctor:
6316 * @this: pointer to an uninitialized delegate object
6317 * @target: target object
6318 * @addr: pointer to native code
6320 * This is used to initialize a delegate.
6323 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6325 MonoDomain *domain = mono_domain_get ();
6327 MonoMethod *method = NULL;
6331 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6333 if (!ji && domain != mono_get_root_domain ())
6334 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6336 method = mono_jit_info_get_method (ji);
6337 g_assert (!method->klass->generic_container);
6340 mono_delegate_ctor_with_method (this, target, addr, method);
6344 * mono_method_call_message_new:
6345 * @method: method to encapsulate
6346 * @params: parameters to the method
6347 * @invoke: optional, delegate invoke.
6348 * @cb: async callback delegate.
6349 * @state: state passed to the async callback.
6351 * Translates arguments pointers into a MonoMethodMessage.
6354 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6355 MonoDelegate **cb, MonoObject **state)
6357 MonoDomain *domain = mono_domain_get ();
6358 MonoMethodSignature *sig = mono_method_signature (method);
6359 MonoMethodMessage *msg;
6362 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6365 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6366 count = sig->param_count - 2;
6368 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6369 count = sig->param_count;
6372 for (i = 0; i < count; i++) {
6377 if (sig->params [i]->byref)
6378 vpos = *((gpointer *)params [i]);
6382 class = mono_class_from_mono_type (sig->params [i]);
6384 if (class->valuetype)
6385 arg = mono_value_box (domain, class, vpos);
6387 arg = *((MonoObject **)vpos);
6389 mono_array_setref (msg->args, i, arg);
6392 if (cb != NULL && state != NULL) {
6393 *cb = *((MonoDelegate **)params [i]);
6395 *state = *((MonoObject **)params [i]);
6402 * mono_method_return_message_restore:
6404 * Restore results from message based processing back to arguments pointers
6407 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6409 MonoMethodSignature *sig = mono_method_signature (method);
6410 int i, j, type, size, out_len;
6412 if (out_args == NULL)
6414 out_len = mono_array_length (out_args);
6418 for (i = 0, j = 0; i < sig->param_count; i++) {
6419 MonoType *pt = sig->params [i];
6424 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6426 arg = mono_array_get (out_args, gpointer, j);
6429 g_assert (type != MONO_TYPE_VOID);
6431 if (MONO_TYPE_IS_REFERENCE (pt)) {
6432 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6435 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6436 size = mono_class_value_size (class, NULL);
6437 if (class->has_references)
6438 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6440 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6442 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6443 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6452 #ifndef DISABLE_REMOTING
6455 * mono_load_remote_field:
6456 * @this: pointer to an object
6457 * @klass: klass of the object containing @field
6458 * @field: the field to load
6459 * @res: a storage to store the result
6461 * This method is called by the runtime on attempts to load fields of
6462 * transparent proxy objects. @this points to such TP, @klass is the class of
6463 * the object containing @field. @res is a storage location which can be
6464 * used to store the result.
6466 * Returns: an address pointing to the value of field.
6469 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6471 static MonoMethod *getter = NULL;
6472 MonoDomain *domain = mono_domain_get ();
6473 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6474 MonoClass *field_class;
6475 MonoMethodMessage *msg;
6476 MonoArray *out_args;
6480 g_assert (mono_object_is_transparent_proxy (this));
6481 g_assert (res != NULL);
6483 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6484 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6489 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6493 field_class = mono_class_from_mono_type (field->type);
6495 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6496 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6497 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6499 full_name = mono_type_get_full_name (klass);
6500 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6501 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6504 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6506 if (exc) mono_raise_exception ((MonoException *)exc);
6508 if (mono_array_length (out_args) == 0)
6511 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6513 if (field_class->valuetype) {
6514 return ((char *)*res) + sizeof (MonoObject);
6520 * mono_load_remote_field_new:
6525 * Missing documentation.
6528 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6530 static MonoMethod *getter = NULL;
6531 MonoDomain *domain = mono_domain_get ();
6532 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6533 MonoClass *field_class;
6534 MonoMethodMessage *msg;
6535 MonoArray *out_args;
6536 MonoObject *exc, *res;
6539 g_assert (mono_object_is_transparent_proxy (this));
6541 field_class = mono_class_from_mono_type (field->type);
6543 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6545 if (field_class->valuetype) {
6546 res = mono_object_new (domain, field_class);
6547 val = ((gchar *) res) + sizeof (MonoObject);
6551 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6556 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6560 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6561 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6563 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6565 full_name = mono_type_get_full_name (klass);
6566 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6567 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6570 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6572 if (exc) mono_raise_exception ((MonoException *)exc);
6574 if (mono_array_length (out_args) == 0)
6577 res = mono_array_get (out_args, MonoObject *, 0);
6583 * mono_store_remote_field:
6584 * @this: pointer to an object
6585 * @klass: klass of the object containing @field
6586 * @field: the field to load
6587 * @val: the value/object to store
6589 * This method is called by the runtime on attempts to store fields of
6590 * transparent proxy objects. @this points to such TP, @klass is the class of
6591 * the object containing @field. @val is the new value to store in @field.
6594 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6596 static MonoMethod *setter = NULL;
6597 MonoDomain *domain = mono_domain_get ();
6598 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6599 MonoClass *field_class;
6600 MonoMethodMessage *msg;
6601 MonoArray *out_args;
6606 g_assert (mono_object_is_transparent_proxy (this));
6608 field_class = mono_class_from_mono_type (field->type);
6610 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6611 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6612 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6617 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6621 if (field_class->valuetype)
6622 arg = mono_value_box (domain, field_class, val);
6624 arg = *((MonoObject **)val);
6627 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6628 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6630 full_name = mono_type_get_full_name (klass);
6631 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6632 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6633 mono_array_setref (msg->args, 2, arg);
6636 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6638 if (exc) mono_raise_exception ((MonoException *)exc);
6642 * mono_store_remote_field_new:
6648 * Missing documentation
6651 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6653 static MonoMethod *setter = NULL;
6654 MonoDomain *domain = mono_domain_get ();
6655 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6656 MonoClass *field_class;
6657 MonoMethodMessage *msg;
6658 MonoArray *out_args;
6662 g_assert (mono_object_is_transparent_proxy (this));
6664 field_class = mono_class_from_mono_type (field->type);
6666 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6667 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6668 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6673 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6677 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6678 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6680 full_name = mono_type_get_full_name (klass);
6681 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6682 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6683 mono_array_setref (msg->args, 2, arg);
6686 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6688 if (exc) mono_raise_exception ((MonoException *)exc);
6693 * mono_create_ftnptr:
6695 * Given a function address, create a function descriptor for it.
6696 * This is only needed on some platforms.
6699 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6701 return callbacks.create_ftnptr (domain, addr);
6705 * mono_get_addr_from_ftnptr:
6707 * Given a pointer to a function descriptor, return the function address.
6708 * This is only needed on some platforms.
6711 mono_get_addr_from_ftnptr (gpointer descr)
6713 return callbacks.get_addr_from_ftnptr (descr);
6717 * mono_string_chars:
6720 * Returns a pointer to the UCS16 characters stored in the MonoString
6723 mono_string_chars (MonoString *s)
6729 * mono_string_length:
6732 * Returns the lenght in characters of the string
6735 mono_string_length (MonoString *s)
6741 * mono_array_length:
6742 * @array: a MonoArray*
6744 * Returns the total number of elements in the array. This works for
6745 * both vectors and multidimensional arrays.
6748 mono_array_length (MonoArray *array)
6750 return array->max_length;
6754 * mono_array_addr_with_size:
6755 * @array: a MonoArray*
6756 * @size: size of the array elements
6757 * @idx: index into the array
6759 * Returns the address of the @idx element in the array.
6762 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6764 return ((char*)(array)->vector) + size * idx;