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)
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/threadpool.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internal.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include "cominterop.h"
50 #define NEED_TO_ZERO_PTRFREE 1
51 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
52 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
53 #ifdef HAVE_GC_GCJ_MALLOC
54 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
62 #define GC_NO_DESCRIPTOR (NULL)
63 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
65 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
67 #define NEED_TO_ZERO_PTRFREE 1
68 #define GC_NO_DESCRIPTOR (NULL)
69 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
70 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
71 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
75 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
76 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
79 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
82 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
85 free_main_args (void);
88 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
91 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
92 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
93 static mono_mutex_t ldstr_section;
95 static gboolean profile_allocs = TRUE;
98 mono_runtime_object_init (MonoObject *this)
100 MonoMethod *method = NULL;
101 MonoClass *klass = this->vtable->klass;
103 method = mono_class_get_method_from_name (klass, ".ctor", 0);
105 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
107 if (method->klass->valuetype)
108 this = mono_object_unbox (this);
109 mono_runtime_invoke (method, this, NULL, NULL);
112 /* The pseudo algorithm for type initialization from the spec
113 Note it doesn't say anything about domains - only threads.
115 2. If the type is initialized you are done.
116 2.1. If the type is not yet initialized, try to take an
118 2.2. If successful, record this thread as responsible for
119 initializing the type and proceed to step 2.3.
120 2.2.1. If not, see whether this thread or any thread
121 waiting for this thread to complete already holds the lock.
122 2.2.2. If so, return since blocking would create a deadlock. This thread
123 will now see an incompletely initialized state for the type,
124 but no deadlock will arise.
125 2.2.3 If not, block until the type is initialized then return.
126 2.3 Initialize the parent type and then all interfaces implemented
128 2.4 Execute the type initialization code for this type.
129 2.5 Mark the type as initialized, release the initialization lock,
130 awaken any threads waiting for this type to be initialized,
137 guint32 initializing_tid;
138 guint32 waiting_count;
140 mono_mutex_t initialization_section;
141 } TypeInitializationLock;
143 /* for locking access to type_initialization_hash and blocked_thread_hash */
144 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
145 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
146 static mono_mutex_t type_initialization_section;
148 /* from vtable to lock */
149 static GHashTable *type_initialization_hash;
151 /* from thread id to thread id being waited on */
152 static GHashTable *blocked_thread_hash;
155 static MonoThread *main_thread;
157 /* Functions supplied by the runtime */
158 static MonoRuntimeCallbacks callbacks;
161 * mono_thread_set_main:
162 * @thread: thread to set as the main thread
164 * This function can be used to instruct the runtime to treat @thread
165 * as the main thread, ie, the thread that would normally execute the Main()
166 * method. This basically means that at the end of @thread, the runtime will
167 * wait for the existing foreground threads to quit and other such details.
170 mono_thread_set_main (MonoThread *thread)
172 static gboolean registered = FALSE;
175 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
179 main_thread = thread;
183 mono_thread_get_main (void)
189 mono_type_initialization_init (void)
191 mono_mutex_init_recursive (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 mono_mutex_init_recursive (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 mono_mutex_destroy (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 mono_mutex_destroy (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MonoDomain *domain = vtable->domain;
224 MonoClass *klass = vtable->klass;
228 if (!vtable->init_failed)
229 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
232 * If the initializing thread was rudely aborted, the exception is not stored
236 mono_domain_lock (domain);
237 if (domain->type_init_exception_hash)
238 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
239 mono_domain_unlock (domain);
242 if (klass->name_space && *klass->name_space)
243 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
245 full_name = g_strdup (klass->name);
246 ex = mono_get_exception_type_initialization (full_name, NULL);
253 * mono_runtime_class_init:
254 * @vtable: vtable that needs to be initialized
256 * This routine calls the class constructor for @vtable.
259 mono_runtime_class_init (MonoVTable *vtable)
261 mono_runtime_class_init_full (vtable, TRUE);
265 * mono_runtime_class_init_full:
266 * @vtable that neeeds to be initialized
267 * @raise_exception is TRUE, exceptions are raised intead of returned
271 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
274 MonoException *exc_to_throw;
275 MonoMethod *method = NULL;
281 if (vtable->initialized)
285 klass = vtable->klass;
287 if (!klass->image->checked_module_cctor) {
288 mono_image_check_for_module_cctor (klass->image);
289 if (klass->image->has_module_cctor) {
291 MonoClass *module_klass;
292 MonoVTable *module_vtable;
294 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
296 exc = mono_error_convert_to_exception (&error);
298 mono_raise_exception (exc);
302 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
305 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
310 method = mono_class_get_cctor (klass);
313 MonoDomain *domain = vtable->domain;
314 TypeInitializationLock *lock;
315 guint32 tid = GetCurrentThreadId();
316 int do_initialization = 0;
317 MonoDomain *last_domain = NULL;
319 mono_type_initialization_lock ();
320 /* double check... */
321 if (vtable->initialized) {
322 mono_type_initialization_unlock ();
325 if (vtable->init_failed) {
326 mono_type_initialization_unlock ();
328 /* The type initialization already failed once, rethrow the same exception */
330 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
331 return get_type_init_exception_for_vtable (vtable);
333 lock = g_hash_table_lookup (type_initialization_hash, vtable);
335 /* This thread will get to do the initialization */
336 if (mono_domain_get () != domain) {
337 /* Transfer into the target domain */
338 last_domain = mono_domain_get ();
339 if (!mono_domain_set (domain, FALSE)) {
340 vtable->initialized = 1;
341 mono_type_initialization_unlock ();
343 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
344 return mono_get_exception_appdomain_unloaded ();
347 lock = g_malloc (sizeof(TypeInitializationLock));
348 mono_mutex_init_recursive (&lock->initialization_section);
349 lock->initializing_tid = tid;
350 lock->waiting_count = 1;
352 /* grab the vtable lock while this thread still owns type_initialization_section */
353 mono_mutex_lock (&lock->initialization_section);
354 g_hash_table_insert (type_initialization_hash, vtable, lock);
355 do_initialization = 1;
358 TypeInitializationLock *pending_lock;
360 if (lock->initializing_tid == tid || lock->done) {
361 mono_type_initialization_unlock ();
364 /* see if the thread doing the initialization is already blocked on this thread */
365 blocked = GUINT_TO_POINTER (lock->initializing_tid);
366 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
367 if (pending_lock->initializing_tid == tid) {
368 if (!pending_lock->done) {
369 mono_type_initialization_unlock ();
372 /* the thread doing the initialization is blocked on this thread,
373 but on a lock that has already been freed. It just hasn't got
378 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
380 ++lock->waiting_count;
381 /* record the fact that we are waiting on the initializing thread */
382 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
384 mono_type_initialization_unlock ();
386 if (do_initialization) {
387 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
389 /* If the initialization failed, mark the class as unusable. */
390 /* Avoid infinite loops */
392 (klass->image == mono_defaults.corlib &&
393 !strcmp (klass->name_space, "System") &&
394 !strcmp (klass->name, "TypeInitializationException")))) {
395 vtable->init_failed = 1;
397 if (klass->name_space && *klass->name_space)
398 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
400 full_name = g_strdup (klass->name);
401 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
405 * Store the exception object so it could be thrown on subsequent
408 mono_domain_lock (domain);
409 if (!domain->type_init_exception_hash)
410 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
411 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
412 mono_domain_unlock (domain);
416 mono_domain_set (last_domain, TRUE);
418 mono_mutex_unlock (&lock->initialization_section);
420 /* this just blocks until the initializing thread is done */
421 mono_mutex_lock (&lock->initialization_section);
422 mono_mutex_unlock (&lock->initialization_section);
425 mono_type_initialization_lock ();
426 if (lock->initializing_tid != tid)
427 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
428 --lock->waiting_count;
429 if (lock->waiting_count == 0) {
430 mono_mutex_destroy (&lock->initialization_section);
431 g_hash_table_remove (type_initialization_hash, vtable);
434 mono_memory_barrier ();
435 if (!vtable->init_failed)
436 vtable->initialized = 1;
437 mono_type_initialization_unlock ();
439 if (vtable->init_failed) {
440 /* Either we were the initializing thread or we waited for the initialization */
442 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
443 return get_type_init_exception_for_vtable (vtable);
446 vtable->initialized = 1;
453 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
455 MonoVTable *vtable = (MonoVTable*)key;
457 TypeInitializationLock *lock = (TypeInitializationLock*) value;
458 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
461 * Have to set this since it cannot be set by the normal code in
462 * mono_runtime_class_init (). In this case, the exception object is not stored,
463 * and get_type_init_exception_for_class () needs to be aware of this.
465 vtable->init_failed = 1;
466 mono_mutex_unlock (&lock->initialization_section);
467 --lock->waiting_count;
468 if (lock->waiting_count == 0) {
469 mono_mutex_destroy (&lock->initialization_section);
478 mono_release_type_locks (MonoInternalThread *thread)
480 mono_type_initialization_lock ();
481 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
482 mono_type_initialization_unlock ();
486 default_trampoline (MonoMethod *method)
492 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
494 g_assert_not_reached ();
499 #ifndef DISABLE_REMOTING
502 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
504 g_error ("remoting not installed");
508 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
512 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
514 g_assert_not_reached ();
518 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
519 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
520 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
521 static MonoImtThunkBuilder imt_thunk_builder = NULL;
522 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
523 #if (MONO_IMT_SIZE > 32)
524 #error "MONO_IMT_SIZE cannot be larger than 32"
528 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
530 memcpy (&callbacks, cbs, sizeof (*cbs));
533 MonoRuntimeCallbacks*
534 mono_get_runtime_callbacks (void)
540 mono_install_trampoline (MonoTrampoline func)
542 arch_create_jit_trampoline = func? func: default_trampoline;
546 mono_install_jump_trampoline (MonoJumpTrampoline func)
548 arch_create_jump_trampoline = func? func: default_jump_trampoline;
551 #ifndef DISABLE_REMOTING
553 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
555 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
560 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
562 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
566 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
567 imt_thunk_builder = func;
570 static MonoCompileFunc default_mono_compile_method = NULL;
573 * mono_install_compile_method:
574 * @func: function to install
576 * This is a VM internal routine
579 mono_install_compile_method (MonoCompileFunc func)
581 default_mono_compile_method = func;
585 * mono_compile_method:
586 * @method: The method to compile.
588 * This JIT-compiles the method, and returns the pointer to the native code
592 mono_compile_method (MonoMethod *method)
594 if (!default_mono_compile_method) {
595 g_error ("compile method called on uninitialized runtime");
598 return default_mono_compile_method (method);
602 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
604 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
608 mono_runtime_create_delegate_trampoline (MonoClass *klass)
610 return arch_create_delegate_trampoline (mono_domain_get (), klass);
613 static MonoFreeMethodFunc default_mono_free_method = NULL;
616 * mono_install_free_method:
617 * @func: pointer to the MonoFreeMethodFunc used to release a method
619 * This is an internal VM routine, it is used for the engines to
620 * register a handler to release the resources associated with a method.
622 * Methods are freed when no more references to the delegate that holds
626 mono_install_free_method (MonoFreeMethodFunc func)
628 default_mono_free_method = func;
632 * mono_runtime_free_method:
633 * @domain; domain where the method is hosted
634 * @method: method to release
636 * This routine is invoked to free the resources associated with
637 * a method that has been JIT compiled. This is used to discard
638 * methods that were used only temporarily (for example, used in marshalling)
642 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
644 if (default_mono_free_method != NULL)
645 default_mono_free_method (domain, method);
647 mono_method_clear_object (domain, method);
649 mono_free_method (method);
653 * The vtables in the root appdomain are assumed to be reachable by other
654 * roots, and we don't use typed allocation in the other domains.
657 /* The sync block is no longer a GC pointer */
658 #define GC_HEADER_BITMAP (0)
660 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
663 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
665 MonoClassField *field;
671 max_size = mono_class_data_size (class) / sizeof (gpointer);
673 max_size = class->instance_size / sizeof (gpointer);
674 if (max_size > size) {
675 g_assert (offset <= 0);
676 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
681 /*An Ephemeron cannot be marked by sgen*/
682 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
684 memset (bitmap, 0, size / 8);
689 for (p = class; p != NULL; p = p->parent) {
690 gpointer iter = NULL;
691 while ((field = mono_class_get_fields (p, &iter))) {
695 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
697 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
700 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
703 /* FIXME: should not happen, flag as type load error */
704 if (field->type->byref)
707 if (static_fields && field->offset == -1)
711 pos = field->offset / sizeof (gpointer);
714 type = mono_type_get_underlying_type (field->type);
715 switch (type->type) {
718 case MONO_TYPE_FNPTR:
720 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
725 if (class->image != mono_defaults.corlib)
728 case MONO_TYPE_STRING:
729 case MONO_TYPE_SZARRAY:
730 case MONO_TYPE_CLASS:
731 case MONO_TYPE_OBJECT:
732 case MONO_TYPE_ARRAY:
733 g_assert ((field->offset % sizeof(gpointer)) == 0);
735 g_assert (pos < size || pos <= max_size);
736 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
737 *max_set = MAX (*max_set, pos);
739 case MONO_TYPE_GENERICINST:
740 if (!mono_type_generic_inst_is_valuetype (type)) {
741 g_assert ((field->offset % sizeof(gpointer)) == 0);
743 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
744 *max_set = MAX (*max_set, pos);
749 case MONO_TYPE_VALUETYPE: {
750 MonoClass *fclass = mono_class_from_mono_type (field->type);
751 if (fclass->has_references) {
752 /* remove the object header */
753 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
767 case MONO_TYPE_BOOLEAN:
771 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
782 * mono_class_compute_bitmap:
784 * Mono internal function to compute a bitmap of reference fields in a class.
787 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
789 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
794 * similar to the above, but sets the bits in the bitmap for any non-ref field
795 * and ignores static fields
798 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
800 MonoClassField *field;
805 max_size = class->instance_size / sizeof (gpointer);
806 if (max_size >= size) {
807 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
810 for (p = class; p != NULL; p = p->parent) {
811 gpointer iter = NULL;
812 while ((field = mono_class_get_fields (p, &iter))) {
815 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
817 /* FIXME: should not happen, flag as type load error */
818 if (field->type->byref)
821 pos = field->offset / sizeof (gpointer);
824 type = mono_type_get_underlying_type (field->type);
825 switch (type->type) {
826 #if SIZEOF_VOID_P == 8
830 case MONO_TYPE_FNPTR:
835 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
836 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
837 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
840 #if SIZEOF_VOID_P == 4
844 case MONO_TYPE_FNPTR:
849 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
850 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
851 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
857 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
858 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
859 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
862 case MONO_TYPE_BOOLEAN:
865 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
867 case MONO_TYPE_STRING:
868 case MONO_TYPE_SZARRAY:
869 case MONO_TYPE_CLASS:
870 case MONO_TYPE_OBJECT:
871 case MONO_TYPE_ARRAY:
873 case MONO_TYPE_GENERICINST:
874 if (!mono_type_generic_inst_is_valuetype (type)) {
879 case MONO_TYPE_VALUETYPE: {
880 MonoClass *fclass = mono_class_from_mono_type (field->type);
881 /* remove the object header */
882 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
886 g_assert_not_reached ();
895 * mono_class_insecure_overlapping:
896 * check if a class with explicit layout has references and non-references
897 * fields overlapping.
899 * Returns: TRUE if it is insecure to load the type.
902 mono_class_insecure_overlapping (MonoClass *klass)
906 gsize default_bitmap [4] = {0};
908 gsize default_nrbitmap [4] = {0};
909 int i, insecure = FALSE;
912 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
913 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
915 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
916 int idx = i % (sizeof (bitmap [0]) * 8);
917 if (bitmap [idx] & nrbitmap [idx]) {
922 if (bitmap != default_bitmap)
924 if (nrbitmap != default_nrbitmap)
927 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
935 mono_string_alloc (int length)
937 return mono_string_new_size (mono_domain_get (), length);
941 mono_class_compute_gc_descriptor (MonoClass *class)
945 gsize default_bitmap [4] = {0};
946 static gboolean gcj_inited = FALSE;
951 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
952 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
953 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
954 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
956 #ifdef HAVE_GC_GCJ_MALLOC
958 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
962 #ifdef GC_REDIRECT_TO_LOCAL
963 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
964 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
966 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
967 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
972 mono_loader_unlock ();
976 mono_class_init (class);
978 if (class->gc_descr_inited)
981 class->gc_descr_inited = TRUE;
982 class->gc_descr = GC_NO_DESCRIPTOR;
984 bitmap = default_bitmap;
985 if (class == mono_defaults.string_class) {
986 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
987 } else if (class->rank) {
988 mono_class_compute_gc_descriptor (class->element_class);
989 if (!class->element_class->valuetype) {
991 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
992 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
993 class->name_space, class->name);*/
995 /* remove the object header */
996 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
997 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));
998 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
999 class->name_space, class->name);*/
1000 if (bitmap != default_bitmap)
1004 /*static int count = 0;
1007 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1008 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1010 if (class->gc_descr == GC_NO_DESCRIPTOR)
1011 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1013 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1014 if (bitmap != default_bitmap)
1020 * field_is_special_static:
1021 * @fklass: The MonoClass to look up.
1022 * @field: The MonoClassField describing the field.
1024 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1025 * SPECIAL_STATIC_NONE otherwise.
1028 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1030 MonoCustomAttrInfo *ainfo;
1032 ainfo = mono_custom_attrs_from_field (fklass, field);
1035 for (i = 0; i < ainfo->num_attrs; ++i) {
1036 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1037 if (klass->image == mono_defaults.corlib) {
1038 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1039 mono_custom_attrs_free (ainfo);
1040 return SPECIAL_STATIC_THREAD;
1042 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1043 mono_custom_attrs_free (ainfo);
1044 return SPECIAL_STATIC_CONTEXT;
1048 mono_custom_attrs_free (ainfo);
1049 return SPECIAL_STATIC_NONE;
1052 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1053 #define mix(a,b,c) { \
1054 a -= c; a ^= rot(c, 4); c += b; \
1055 b -= a; b ^= rot(a, 6); a += c; \
1056 c -= b; c ^= rot(b, 8); b += a; \
1057 a -= c; a ^= rot(c,16); c += b; \
1058 b -= a; b ^= rot(a,19); a += c; \
1059 c -= b; c ^= rot(b, 4); b += a; \
1061 #define final(a,b,c) { \
1062 c ^= b; c -= rot(b,14); \
1063 a ^= c; a -= rot(c,11); \
1064 b ^= a; b -= rot(a,25); \
1065 c ^= b; c -= rot(b,16); \
1066 a ^= c; a -= rot(c,4); \
1067 b ^= a; b -= rot(a,14); \
1068 c ^= b; c -= rot(b,24); \
1072 * mono_method_get_imt_slot:
1074 * The IMT slot is embedded into AOTed code, so this must return the same value
1075 * for the same method across all executions. This means:
1076 * - pointers shouldn't be used as hash values.
1077 * - mono_metadata_str_hash () should be used for hashing strings.
1080 mono_method_get_imt_slot (MonoMethod *method)
1082 MonoMethodSignature *sig;
1084 guint32 *hashes_start, *hashes;
1088 /* This can be used to stress tests the collision code */
1092 * We do this to simplify generic sharing. It will hurt
1093 * performance in cases where a class implements two different
1094 * instantiations of the same generic interface.
1095 * The code in build_imt_slots () depends on this.
1097 if (method->is_inflated)
1098 method = ((MonoMethodInflated*)method)->declaring;
1100 sig = mono_method_signature (method);
1101 hashes_count = sig->param_count + 4;
1102 hashes_start = malloc (hashes_count * sizeof (guint32));
1103 hashes = hashes_start;
1105 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1106 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1107 method->klass->name_space, method->klass->name, method->name);
1110 /* Initialize hashes */
1111 hashes [0] = mono_metadata_str_hash (method->klass->name);
1112 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1113 hashes [2] = mono_metadata_str_hash (method->name);
1114 hashes [3] = mono_metadata_type_hash (sig->ret);
1115 for (i = 0; i < sig->param_count; i++) {
1116 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1119 /* Setup internal state */
1120 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1122 /* Handle most of the hashes */
1123 while (hashes_count > 3) {
1132 /* Handle the last 3 hashes (all the case statements fall through) */
1133 switch (hashes_count) {
1134 case 3 : c += hashes [2];
1135 case 2 : b += hashes [1];
1136 case 1 : a += hashes [0];
1138 case 0: /* nothing left to add */
1142 free (hashes_start);
1143 /* Report the result */
1144 return c % MONO_IMT_SIZE;
1153 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1154 guint32 imt_slot = mono_method_get_imt_slot (method);
1155 MonoImtBuilderEntry *entry;
1157 if (slot_num >= 0 && imt_slot != slot_num) {
1158 /* we build just a single imt slot and this is not it */
1162 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1163 entry->key = method;
1164 entry->value.vtable_slot = vtable_slot;
1165 entry->next = imt_builder [imt_slot];
1166 if (imt_builder [imt_slot] != NULL) {
1167 entry->children = imt_builder [imt_slot]->children + 1;
1168 if (entry->children == 1) {
1169 mono_stats.imt_slots_with_collisions++;
1170 *imt_collisions_bitmap |= (1 << imt_slot);
1173 entry->children = 0;
1174 mono_stats.imt_used_slots++;
1176 imt_builder [imt_slot] = entry;
1179 char *method_name = mono_method_full_name (method, TRUE);
1180 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1181 method, method_name, imt_slot, vtable_slot, entry->children);
1182 g_free (method_name);
1189 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1191 MonoMethod *method = e->key;
1192 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1196 method->klass->name_space,
1197 method->klass->name,
1200 printf (" * %s: NULL\n", message);
1206 compare_imt_builder_entries (const void *p1, const void *p2) {
1207 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1208 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1210 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1214 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1216 int count = end - start;
1217 int chunk_start = out_array->len;
1220 for (i = start; i < end; ++i) {
1221 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1222 item->key = sorted_array [i]->key;
1223 item->value = sorted_array [i]->value;
1224 item->has_target_code = sorted_array [i]->has_target_code;
1225 item->is_equals = TRUE;
1227 item->check_target_idx = out_array->len + 1;
1229 item->check_target_idx = 0;
1230 g_ptr_array_add (out_array, item);
1233 int middle = start + count / 2;
1234 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1236 item->key = sorted_array [middle]->key;
1237 item->is_equals = FALSE;
1238 g_ptr_array_add (out_array, item);
1239 imt_emit_ir (sorted_array, start, middle, out_array);
1240 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1246 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1247 int number_of_entries = entries->children + 1;
1248 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1249 GPtrArray *result = g_ptr_array_new ();
1250 MonoImtBuilderEntry *current_entry;
1253 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1254 sorted_array [i] = current_entry;
1256 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1258 /*for (i = 0; i < number_of_entries; i++) {
1259 print_imt_entry (" sorted array:", sorted_array [i], i);
1262 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1264 free (sorted_array);
1269 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1271 if (imt_builder_entry != NULL) {
1272 if (imt_builder_entry->children == 0 && !fail_tramp) {
1273 /* No collision, return the vtable slot contents */
1274 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1276 /* Collision, build the thunk */
1277 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1280 result = imt_thunk_builder (vtable, domain,
1281 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1282 for (i = 0; i < imt_ir->len; ++i)
1283 g_free (g_ptr_array_index (imt_ir, i));
1284 g_ptr_array_free (imt_ir, TRUE);
1296 static MonoImtBuilderEntry*
1297 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1300 * LOCKING: requires the loader and domain locks.
1304 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1308 guint32 imt_collisions_bitmap = 0;
1309 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1310 int method_count = 0;
1311 gboolean record_method_count_for_max_collisions = FALSE;
1312 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1315 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1317 for (i = 0; i < klass->interface_offsets_count; ++i) {
1318 MonoClass *iface = klass->interfaces_packed [i];
1319 int interface_offset = klass->interface_offsets_packed [i];
1320 int method_slot_in_interface, vt_slot;
1322 if (mono_class_has_variant_generic_params (iface))
1323 has_variant_iface = TRUE;
1325 mono_class_setup_methods (iface);
1326 vt_slot = interface_offset;
1327 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1330 if (slot_num >= 0 && iface->is_inflated) {
1332 * The imt slot of the method is the same as for its declaring method,
1333 * see the comment in mono_method_get_imt_slot (), so we can
1334 * avoid inflating methods which will be discarded by
1335 * add_imt_builder_entry anyway.
1337 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1338 if (mono_method_get_imt_slot (method) != slot_num) {
1343 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1344 if (method->is_generic) {
1345 has_generic_virtual = TRUE;
1350 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1351 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1356 if (extra_interfaces) {
1357 int interface_offset = klass->vtable_size;
1359 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1360 MonoClass* iface = list_item->data;
1361 int method_slot_in_interface;
1362 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1363 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1365 if (method->is_generic)
1366 has_generic_virtual = TRUE;
1367 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1369 interface_offset += iface->method.count;
1372 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1373 /* overwrite the imt slot only if we're building all the entries or if
1374 * we're building this specific one
1376 if (slot_num < 0 || i == slot_num) {
1377 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1380 if (imt_builder [i]) {
1381 MonoImtBuilderEntry *entry;
1383 /* Link entries with imt_builder [i] */
1384 for (entry = entries; entry->next; entry = entry->next) {
1386 MonoMethod *method = (MonoMethod*)entry->key;
1387 char *method_name = mono_method_full_name (method, TRUE);
1388 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1389 g_free (method_name);
1392 entry->next = imt_builder [i];
1393 entries->children += imt_builder [i]->children + 1;
1395 imt_builder [i] = entries;
1398 if (has_generic_virtual || has_variant_iface) {
1400 * There might be collisions later when the the thunk is expanded.
1402 imt_collisions_bitmap |= (1 << i);
1405 * The IMT thunk might be called with an instance of one of the
1406 * generic virtual methods, so has to fallback to the IMT trampoline.
1408 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1410 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1413 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1417 if (imt_builder [i] != NULL) {
1418 int methods_in_slot = imt_builder [i]->children + 1;
1419 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1420 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1421 record_method_count_for_max_collisions = TRUE;
1423 method_count += methods_in_slot;
1427 mono_stats.imt_number_of_methods += method_count;
1428 if (record_method_count_for_max_collisions) {
1429 mono_stats.imt_method_count_when_max_collisions = method_count;
1432 for (i = 0; i < MONO_IMT_SIZE; i++) {
1433 MonoImtBuilderEntry* entry = imt_builder [i];
1434 while (entry != NULL) {
1435 MonoImtBuilderEntry* next = entry->next;
1441 /* we OR the bitmap since we may build just a single imt slot at a time */
1442 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1446 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1447 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1451 * mono_vtable_build_imt_slot:
1452 * @vtable: virtual object table struct
1453 * @imt_slot: slot in the IMT table
1455 * Fill the given @imt_slot in the IMT table of @vtable with
1456 * a trampoline or a thunk for the case of collisions.
1457 * This is part of the internal mono API.
1459 * LOCKING: Take the domain lock.
1462 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1464 gpointer *imt = (gpointer*)vtable;
1465 imt -= MONO_IMT_SIZE;
1466 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1468 /* no support for extra interfaces: the proxy objects will need
1469 * to build the complete IMT
1470 * Update and heck needs to ahppen inside the proper domain lock, as all
1471 * the changes made to a MonoVTable.
1473 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1474 mono_domain_lock (vtable->domain);
1475 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1476 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1477 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1478 mono_domain_unlock (vtable->domain);
1479 mono_loader_unlock ();
1484 * The first two free list entries both belong to the wait list: The
1485 * first entry is the pointer to the head of the list and the second
1486 * entry points to the last element. That way appending and removing
1487 * the first element are both O(1) operations.
1489 #ifdef MONO_SMALL_CONFIG
1490 #define NUM_FREE_LISTS 6
1492 #define NUM_FREE_LISTS 12
1494 #define FIRST_FREE_LIST_SIZE 64
1495 #define MAX_WAIT_LENGTH 50
1496 #define THUNK_THRESHOLD 10
1499 * LOCKING: The domain lock must be held.
1502 init_thunk_free_lists (MonoDomain *domain)
1504 if (domain->thunk_free_lists)
1506 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1510 list_index_for_size (int item_size)
1513 int size = FIRST_FREE_LIST_SIZE;
1515 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1524 * mono_method_alloc_generic_virtual_thunk:
1526 * @size: size in bytes
1528 * Allocs size bytes to be used for the code of a generic virtual
1529 * thunk. It's either allocated from the domain's code manager or
1530 * reused from a previously invalidated piece.
1532 * LOCKING: The domain lock must be held.
1535 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1537 static gboolean inited = FALSE;
1538 static int generic_virtual_thunks_size = 0;
1542 MonoThunkFreeList **l;
1544 init_thunk_free_lists (domain);
1546 size += sizeof (guint32);
1547 if (size < sizeof (MonoThunkFreeList))
1548 size = sizeof (MonoThunkFreeList);
1550 i = list_index_for_size (size);
1551 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1552 if ((*l)->size >= size) {
1553 MonoThunkFreeList *item = *l;
1555 return ((guint32*)item) + 1;
1559 /* no suitable item found - search lists of larger sizes */
1560 while (++i < NUM_FREE_LISTS) {
1561 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1564 g_assert (item->size > size);
1565 domain->thunk_free_lists [i] = item->next;
1566 return ((guint32*)item) + 1;
1569 /* still nothing found - allocate it */
1571 mono_counters_register ("Generic virtual thunk bytes",
1572 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1575 generic_virtual_thunks_size += size;
1577 p = mono_domain_code_reserve (domain, size);
1580 mono_domain_lock (domain);
1581 if (!domain->generic_virtual_thunks)
1582 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1583 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1584 mono_domain_unlock (domain);
1590 * LOCKING: The domain lock must be held.
1593 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1596 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1597 gboolean found = FALSE;
1599 mono_domain_lock (domain);
1600 if (!domain->generic_virtual_thunks)
1601 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1602 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1604 mono_domain_unlock (domain);
1607 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1609 init_thunk_free_lists (domain);
1611 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1612 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1613 int length = item->length;
1616 /* unlink the first item from the wait list */
1617 domain->thunk_free_lists [0] = item->next;
1618 domain->thunk_free_lists [0]->length = length - 1;
1620 i = list_index_for_size (item->size);
1622 /* put it in the free list */
1623 item->next = domain->thunk_free_lists [i];
1624 domain->thunk_free_lists [i] = item;
1628 if (domain->thunk_free_lists [1]) {
1629 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1630 domain->thunk_free_lists [0]->length++;
1632 g_assert (!domain->thunk_free_lists [0]);
1634 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1635 domain->thunk_free_lists [0]->length = 1;
1639 typedef struct _GenericVirtualCase {
1643 struct _GenericVirtualCase *next;
1644 } GenericVirtualCase;
1647 * get_generic_virtual_entries:
1649 * Return IMT entries for the generic virtual method instances and
1650 * variant interface methods for vtable slot
1653 static MonoImtBuilderEntry*
1654 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1656 GenericVirtualCase *list;
1657 MonoImtBuilderEntry *entries;
1659 mono_domain_lock (domain);
1660 if (!domain->generic_virtual_cases)
1661 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1663 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1666 for (; list; list = list->next) {
1667 MonoImtBuilderEntry *entry;
1669 if (list->count < THUNK_THRESHOLD)
1672 entry = g_new0 (MonoImtBuilderEntry, 1);
1673 entry->key = list->method;
1674 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1675 entry->has_target_code = 1;
1677 entry->children = entries->children + 1;
1678 entry->next = entries;
1682 mono_domain_unlock (domain);
1684 /* FIXME: Leaking memory ? */
1689 * mono_method_add_generic_virtual_invocation:
1691 * @vtable_slot: pointer to the vtable slot
1692 * @method: the inflated generic virtual method
1693 * @code: the method's code
1695 * Registers a call via unmanaged code to a generic virtual method
1696 * instantiation or variant interface method. If the number of calls reaches a threshold
1697 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1698 * virtual method thunk.
1701 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1702 gpointer *vtable_slot,
1703 MonoMethod *method, gpointer code)
1705 static gboolean inited = FALSE;
1706 static int num_added = 0;
1708 GenericVirtualCase *gvc, *list;
1709 MonoImtBuilderEntry *entries;
1713 mono_domain_lock (domain);
1714 if (!domain->generic_virtual_cases)
1715 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1717 /* Check whether the case was already added */
1718 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1721 if (gvc->method == method)
1726 /* If not found, make a new one */
1728 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1729 gvc->method = method;
1732 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1734 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1737 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1743 if (++gvc->count == THUNK_THRESHOLD) {
1744 gpointer *old_thunk = *vtable_slot;
1745 gpointer vtable_trampoline = NULL;
1746 gpointer imt_trampoline = NULL;
1748 if ((gpointer)vtable_slot < (gpointer)vtable) {
1749 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1750 int imt_slot = MONO_IMT_SIZE + displacement;
1752 /* Force the rebuild of the thunk at the next call */
1753 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1754 *vtable_slot = imt_trampoline;
1756 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1758 entries = get_generic_virtual_entries (domain, vtable_slot);
1760 sorted = imt_sort_slot_entries (entries);
1762 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1766 MonoImtBuilderEntry *next = entries->next;
1771 for (i = 0; i < sorted->len; ++i)
1772 g_free (g_ptr_array_index (sorted, i));
1773 g_ptr_array_free (sorted, TRUE);
1776 #ifndef __native_client__
1777 /* We don't re-use any thunks as there is a lot of overhead */
1778 /* to deleting and re-using code in Native Client. */
1779 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1780 invalidate_generic_virtual_thunk (domain, old_thunk);
1784 mono_domain_unlock (domain);
1787 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1790 * mono_class_vtable:
1791 * @domain: the application domain
1792 * @class: the class to initialize
1794 * VTables are domain specific because we create domain specific code, and
1795 * they contain the domain specific static class data.
1796 * On failure, NULL is returned, and class->exception_type is set.
1799 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1801 return mono_class_vtable_full (domain, class, FALSE);
1805 * mono_class_vtable_full:
1806 * @domain: the application domain
1807 * @class: the class to initialize
1808 * @raise_on_error if an exception should be raised on failure or not
1810 * VTables are domain specific because we create domain specific code, and
1811 * they contain the domain specific static class data.
1814 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1816 MonoClassRuntimeInfo *runtime_info;
1820 if (class->exception_type) {
1822 mono_raise_exception (mono_class_get_exception_for_failure (class));
1826 /* this check can be inlined in jitted code, too */
1827 runtime_info = class->runtime_info;
1828 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1829 return runtime_info->domain_vtables [domain->domain_id];
1830 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1834 * mono_class_try_get_vtable:
1835 * @domain: the application domain
1836 * @class: the class to initialize
1838 * This function tries to get the associated vtable from @class if
1839 * it was already created.
1842 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1844 MonoClassRuntimeInfo *runtime_info;
1848 runtime_info = class->runtime_info;
1849 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1850 return runtime_info->domain_vtables [domain->domain_id];
1855 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1858 MonoClassRuntimeInfo *runtime_info, *old_info;
1859 MonoClassField *field;
1861 int i, vtable_slots;
1862 int imt_table_bytes = 0;
1864 guint32 vtable_size, class_size;
1867 gpointer *interface_offsets;
1869 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1870 mono_domain_lock (domain);
1871 runtime_info = class->runtime_info;
1872 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1873 mono_domain_unlock (domain);
1874 mono_loader_unlock ();
1875 return runtime_info->domain_vtables [domain->domain_id];
1877 if (!class->inited || class->exception_type) {
1878 if (!mono_class_init (class) || class->exception_type) {
1879 mono_domain_unlock (domain);
1880 mono_loader_unlock ();
1882 mono_raise_exception (mono_class_get_exception_for_failure (class));
1887 /* Array types require that their element type be valid*/
1888 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1889 MonoClass *element_class = class->element_class;
1890 if (!element_class->inited)
1891 mono_class_init (element_class);
1893 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1894 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1895 mono_class_setup_vtable (element_class);
1897 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1898 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1899 if (class->exception_type == MONO_EXCEPTION_NONE)
1900 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1901 mono_domain_unlock (domain);
1902 mono_loader_unlock ();
1904 mono_raise_exception (mono_class_get_exception_for_failure (class));
1910 * For some classes, mono_class_init () already computed class->vtable_size, and
1911 * that is all that is needed because of the vtable trampolines.
1913 if (!class->vtable_size)
1914 mono_class_setup_vtable (class);
1916 if (class->generic_class && !class->vtable)
1917 mono_class_check_vtable_constraints (class, NULL);
1919 /* Initialize klass->has_finalize */
1920 mono_class_has_finalizer (class);
1922 if (class->exception_type) {
1923 mono_domain_unlock (domain);
1924 mono_loader_unlock ();
1926 mono_raise_exception (mono_class_get_exception_for_failure (class));
1930 vtable_slots = class->vtable_size;
1931 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1932 class_size = mono_class_data_size (class);
1937 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1938 if (class->interface_offsets_count) {
1939 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1940 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1941 mono_stats.imt_number_of_tables++;
1942 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1945 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1946 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1949 mono_stats.used_class_count++;
1950 mono_stats.class_vtable_size += vtable_size;
1951 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1954 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1956 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1958 vt->rank = class->rank;
1959 vt->domain = domain;
1961 mono_class_compute_gc_descriptor (class);
1963 * We can't use typed allocation in the non-root domains, since the
1964 * collector needs the GC descriptor stored in the vtable even after
1965 * the mempool containing the vtable is destroyed when the domain is
1966 * unloaded. An alternative might be to allocate vtables in the GC
1967 * heap, but this does not seem to work (it leads to crashes inside
1968 * libgc). If that approach is tried, two gc descriptors need to be
1969 * allocated for each class: one for the root domain, and one for all
1970 * other domains. The second descriptor should contain a bit for the
1971 * vtable field in MonoObject, since we can no longer assume the
1972 * vtable is reachable by other roots after the appdomain is unloaded.
1974 #ifdef HAVE_BOEHM_GC
1975 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1976 vt->gc_descr = GC_NO_DESCRIPTOR;
1979 vt->gc_descr = class->gc_descr;
1981 gc_bits = mono_gc_get_vtable_bits (class);
1982 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1984 vt->gc_bits = gc_bits;
1987 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1988 if (class->has_static_refs) {
1989 gpointer statics_gc_descr;
1991 gsize default_bitmap [4] = {0};
1994 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1995 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1996 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1997 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1998 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
1999 if (bitmap != default_bitmap)
2002 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2004 vt->has_static_fields = TRUE;
2005 mono_stats.class_static_data_size += class_size;
2010 while ((field = mono_class_get_fields (class, &iter))) {
2011 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2013 if (mono_field_is_deleted (field))
2015 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2016 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2017 if (special_static != SPECIAL_STATIC_NONE) {
2018 guint32 size, offset;
2020 gsize default_bitmap [4] = {0};
2025 if (mono_type_is_reference (field->type)) {
2026 default_bitmap [0] = 1;
2028 bitmap = default_bitmap;
2029 } else if (mono_type_is_struct (field->type)) {
2030 fclass = mono_class_from_mono_type (field->type);
2031 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2032 numbits = max_set + 1;
2034 default_bitmap [0] = 0;
2036 bitmap = default_bitmap;
2038 size = mono_type_size (field->type, &align);
2039 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2040 if (!domain->special_static_fields)
2041 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2042 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2043 if (bitmap != default_bitmap)
2046 * This marks the field as special static to speed up the
2047 * checks in mono_field_static_get/set_value ().
2053 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2054 MonoClass *fklass = mono_class_from_mono_type (field->type);
2055 const char *data = mono_field_get_data (field);
2057 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2058 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2059 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2062 if (fklass->valuetype) {
2063 memcpy (t, data, mono_class_value_size (fklass, NULL));
2065 /* it's a pointer type: add check */
2066 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2073 vt->max_interface_id = class->max_interface_id;
2074 vt->interface_bitmap = class->interface_bitmap;
2076 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2077 // class->name, class->interface_offsets_count);
2079 if (! ARCH_USE_IMT) {
2080 /* initialize interface offsets */
2081 for (i = 0; i < class->interface_offsets_count; ++i) {
2082 int interface_id = class->interfaces_packed [i]->interface_id;
2083 int slot = class->interface_offsets_packed [i];
2084 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2088 /* Initialize vtable */
2089 if (callbacks.get_vtable_trampoline) {
2090 // This also covers the AOT case
2091 for (i = 0; i < class->vtable_size; ++i) {
2092 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2095 mono_class_setup_vtable (class);
2097 for (i = 0; i < class->vtable_size; ++i) {
2100 if ((cm = class->vtable [i]))
2101 vt->vtable [i] = arch_create_jit_trampoline (cm);
2105 if (ARCH_USE_IMT && imt_table_bytes) {
2106 /* Now that the vtable is full, we can actually fill up the IMT */
2107 if (callbacks.get_imt_trampoline) {
2108 /* lazy construction of the IMT entries enabled */
2109 for (i = 0; i < MONO_IMT_SIZE; ++i)
2110 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2112 build_imt (class, vt, domain, interface_offsets, NULL);
2117 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2118 * re-acquire them and check if another thread has created the vtable in the meantime.
2120 /* Special case System.MonoType to avoid infinite recursion */
2121 if (class != mono_defaults.monotype_class) {
2122 /*FIXME check for OOM*/
2123 vt->type = mono_type_get_object (domain, &class->byval_arg);
2124 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2125 /* This is unregistered in
2126 unregister_vtable_reflection_type() in
2128 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2131 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2133 /* class_vtable_array keeps an array of created vtables
2135 g_ptr_array_add (domain->class_vtable_array, vt);
2136 /* class->runtime_info is protected by the loader lock, both when
2137 * it it enlarged and when it is stored info.
2141 * Store the vtable in class->runtime_info.
2142 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2144 mono_memory_barrier ();
2146 old_info = class->runtime_info;
2147 if (old_info && old_info->max_domain >= domain->domain_id) {
2148 /* someone already created a large enough runtime info */
2149 old_info->domain_vtables [domain->domain_id] = vt;
2151 int new_size = domain->domain_id;
2153 new_size = MAX (new_size, old_info->max_domain);
2155 /* make the new size a power of two */
2157 while (new_size > i)
2160 /* this is a bounded memory retention issue: may want to
2161 * handle it differently when we'll have a rcu-like system.
2163 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2164 runtime_info->max_domain = new_size - 1;
2165 /* copy the stuff from the older info */
2167 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2169 runtime_info->domain_vtables [domain->domain_id] = vt;
2171 mono_memory_barrier ();
2172 class->runtime_info = runtime_info;
2175 if (class == mono_defaults.monotype_class) {
2176 /*FIXME check for OOM*/
2177 vt->type = mono_type_get_object (domain, &class->byval_arg);
2178 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2179 /* This is unregistered in
2180 unregister_vtable_reflection_type() in
2182 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2185 mono_domain_unlock (domain);
2186 mono_loader_unlock ();
2188 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2189 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2190 mono_raise_exception (mono_class_get_exception_for_failure (class));
2192 /* make sure the parent is initialized */
2193 /*FIXME shouldn't this fail the current type?*/
2195 mono_class_vtable_full (domain, class->parent, raise_on_error);
2200 #ifndef DISABLE_REMOTING
2202 * mono_class_proxy_vtable:
2203 * @domain: the application domain
2204 * @remove_class: the remote class
2206 * Creates a vtable for transparent proxies. It is basically
2207 * a copy of the real vtable of the class wrapped in @remote_class,
2208 * but all function pointers invoke the remoting functions, and
2209 * vtable->klass points to the transparent proxy class, and not to @class.
2212 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2215 MonoVTable *vt, *pvt;
2216 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2218 GSList *extra_interfaces = NULL;
2219 MonoClass *class = remote_class->proxy_class;
2220 gpointer *interface_offsets;
2224 #ifdef COMPRESSED_INTERFACE_BITMAP
2228 vt = mono_class_vtable (domain, class);
2229 g_assert (vt); /*FIXME property handle failure*/
2230 max_interface_id = vt->max_interface_id;
2232 /* Calculate vtable space for extra interfaces */
2233 for (j = 0; j < remote_class->interface_count; j++) {
2234 MonoClass* iclass = remote_class->interfaces[j];
2238 /*FIXME test for interfaces with variant generic arguments*/
2239 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2240 continue; /* interface implemented by the class */
2241 if (g_slist_find (extra_interfaces, iclass))
2244 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2246 method_count = mono_class_num_methods (iclass);
2248 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2249 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2251 for (i = 0; i < ifaces->len; ++i) {
2252 MonoClass *ic = g_ptr_array_index (ifaces, i);
2253 /*FIXME test for interfaces with variant generic arguments*/
2254 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2255 continue; /* interface implemented by the class */
2256 if (g_slist_find (extra_interfaces, ic))
2258 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2259 method_count += mono_class_num_methods (ic);
2261 g_ptr_array_free (ifaces, TRUE);
2264 extra_interface_vtsize += method_count * sizeof (gpointer);
2265 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2269 mono_stats.imt_number_of_tables++;
2270 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2271 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2272 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2274 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2275 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2278 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2280 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2282 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2284 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2285 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2287 pvt->klass = mono_defaults.transparent_proxy_class;
2288 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2289 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2291 /* initialize vtable */
2292 mono_class_setup_vtable (class);
2293 for (i = 0; i < class->vtable_size; ++i) {
2296 if ((cm = class->vtable [i]))
2297 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2299 pvt->vtable [i] = NULL;
2302 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2303 /* create trampolines for abstract methods */
2304 for (k = class; k; k = k->parent) {
2306 gpointer iter = NULL;
2307 while ((m = mono_class_get_methods (k, &iter)))
2308 if (!pvt->vtable [m->slot])
2309 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2313 pvt->max_interface_id = max_interface_id;
2314 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2315 #ifdef COMPRESSED_INTERFACE_BITMAP
2316 bitmap = g_malloc0 (bsize);
2318 bitmap = mono_domain_alloc0 (domain, bsize);
2321 if (! ARCH_USE_IMT) {
2322 /* initialize interface offsets */
2323 for (i = 0; i < class->interface_offsets_count; ++i) {
2324 int interface_id = class->interfaces_packed [i]->interface_id;
2325 int slot = class->interface_offsets_packed [i];
2326 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2329 for (i = 0; i < class->interface_offsets_count; ++i) {
2330 int interface_id = class->interfaces_packed [i]->interface_id;
2331 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2334 if (extra_interfaces) {
2335 int slot = class->vtable_size;
2341 /* Create trampolines for the methods of the interfaces */
2342 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2343 interf = list_item->data;
2345 if (! ARCH_USE_IMT) {
2346 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2348 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2352 while ((cm = mono_class_get_methods (interf, &iter)))
2353 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2355 slot += mono_class_num_methods (interf);
2357 if (! ARCH_USE_IMT) {
2358 g_slist_free (extra_interfaces);
2363 /* Now that the vtable is full, we can actually fill up the IMT */
2364 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2365 if (extra_interfaces) {
2366 g_slist_free (extra_interfaces);
2370 #ifdef COMPRESSED_INTERFACE_BITMAP
2371 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2372 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2373 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2376 pvt->interface_bitmap = bitmap;
2381 #endif /* DISABLE_REMOTING */
2384 * mono_class_field_is_special_static:
2386 * Returns whether @field is a thread/context static field.
2389 mono_class_field_is_special_static (MonoClassField *field)
2391 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2393 if (mono_field_is_deleted (field))
2395 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2396 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2403 * mono_class_field_get_special_static_type:
2404 * @field: The MonoClassField describing the field.
2406 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2407 * SPECIAL_STATIC_NONE otherwise.
2410 mono_class_field_get_special_static_type (MonoClassField *field)
2412 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2413 return SPECIAL_STATIC_NONE;
2414 if (mono_field_is_deleted (field))
2415 return SPECIAL_STATIC_NONE;
2416 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2417 return field_is_special_static (field->parent, field);
2418 return SPECIAL_STATIC_NONE;
2422 * mono_class_has_special_static_fields:
2424 * Returns whenever @klass has any thread/context static fields.
2427 mono_class_has_special_static_fields (MonoClass *klass)
2429 MonoClassField *field;
2433 while ((field = mono_class_get_fields (klass, &iter))) {
2434 g_assert (field->parent == klass);
2435 if (mono_class_field_is_special_static (field))
2442 #ifndef DISABLE_REMOTING
2444 * create_remote_class_key:
2445 * Creates an array of pointers that can be used as a hash key for a remote class.
2446 * The first element of the array is the number of pointers.
2449 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2454 if (remote_class == NULL) {
2455 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2456 key = g_malloc (sizeof(gpointer) * 3);
2457 key [0] = GINT_TO_POINTER (2);
2458 key [1] = mono_defaults.marshalbyrefobject_class;
2459 key [2] = extra_class;
2461 key = g_malloc (sizeof(gpointer) * 2);
2462 key [0] = GINT_TO_POINTER (1);
2463 key [1] = extra_class;
2466 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2467 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2468 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2469 key [1] = remote_class->proxy_class;
2471 // Keep the list of interfaces sorted
2472 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2473 if (extra_class && remote_class->interfaces [i] > extra_class) {
2474 key [j++] = extra_class;
2477 key [j] = remote_class->interfaces [i];
2480 key [j] = extra_class;
2482 // Replace the old class. The interface list is the same
2483 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2484 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2485 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2486 for (i = 0; i < remote_class->interface_count; i++)
2487 key [2 + i] = remote_class->interfaces [i];
2495 * copy_remote_class_key:
2497 * Make a copy of KEY in the domain and return the copy.
2500 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2502 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2503 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2505 memcpy (mp_key, key, key_size);
2511 * mono_remote_class:
2512 * @domain: the application domain
2513 * @class_name: name of the remote class
2515 * Creates and initializes a MonoRemoteClass object for a remote type.
2517 * Can raise an exception on failure.
2520 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2523 MonoRemoteClass *rc;
2524 gpointer* key, *mp_key;
2527 key = create_remote_class_key (NULL, proxy_class);
2529 mono_domain_lock (domain);
2530 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2534 mono_domain_unlock (domain);
2538 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2539 if (!mono_error_ok (&error)) {
2541 mono_domain_unlock (domain);
2542 mono_error_raise_exception (&error);
2545 mp_key = copy_remote_class_key (domain, key);
2549 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2550 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2551 rc->interface_count = 1;
2552 rc->interfaces [0] = proxy_class;
2553 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2555 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2556 rc->interface_count = 0;
2557 rc->proxy_class = proxy_class;
2560 rc->default_vtable = NULL;
2561 rc->xdomain_vtable = NULL;
2562 rc->proxy_class_name = name;
2563 #ifndef DISABLE_PERFCOUNTERS
2564 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2567 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2569 mono_domain_unlock (domain);
2574 * clone_remote_class:
2575 * Creates a copy of the remote_class, adding the provided class or interface
2577 static MonoRemoteClass*
2578 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2580 MonoRemoteClass *rc;
2581 gpointer* key, *mp_key;
2583 key = create_remote_class_key (remote_class, extra_class);
2584 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2590 mp_key = copy_remote_class_key (domain, key);
2594 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2596 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2597 rc->proxy_class = remote_class->proxy_class;
2598 rc->interface_count = remote_class->interface_count + 1;
2600 // Keep the list of interfaces sorted, since the hash key of
2601 // the remote class depends on this
2602 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2603 if (remote_class->interfaces [i] > extra_class && i == j)
2604 rc->interfaces [j++] = extra_class;
2605 rc->interfaces [j] = remote_class->interfaces [i];
2608 rc->interfaces [j] = extra_class;
2610 // Replace the old class. The interface array is the same
2611 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2612 rc->proxy_class = extra_class;
2613 rc->interface_count = remote_class->interface_count;
2614 if (rc->interface_count > 0)
2615 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2618 rc->default_vtable = NULL;
2619 rc->xdomain_vtable = NULL;
2620 rc->proxy_class_name = remote_class->proxy_class_name;
2622 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2628 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2630 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2631 mono_domain_lock (domain);
2632 if (rp->target_domain_id != -1) {
2633 if (remote_class->xdomain_vtable == NULL)
2634 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2635 mono_domain_unlock (domain);
2636 mono_loader_unlock ();
2637 return remote_class->xdomain_vtable;
2639 if (remote_class->default_vtable == NULL) {
2642 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2643 klass = mono_class_from_mono_type (type);
2645 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)))
2646 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2649 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2652 mono_domain_unlock (domain);
2653 mono_loader_unlock ();
2654 return remote_class->default_vtable;
2658 * mono_upgrade_remote_class:
2659 * @domain: the application domain
2660 * @tproxy: the proxy whose remote class has to be upgraded.
2661 * @klass: class to which the remote class can be casted.
2663 * Updates the vtable of the remote class by adding the necessary method slots
2664 * and interface offsets so it can be safely casted to klass. klass can be a
2665 * class or an interface.
2668 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2670 MonoTransparentProxy *tproxy;
2671 MonoRemoteClass *remote_class;
2672 gboolean redo_vtable;
2674 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2675 mono_domain_lock (domain);
2677 tproxy = (MonoTransparentProxy*) proxy_object;
2678 remote_class = tproxy->remote_class;
2680 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2683 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2684 if (remote_class->interfaces [i] == klass)
2685 redo_vtable = FALSE;
2688 redo_vtable = (remote_class->proxy_class != klass);
2692 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2693 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2696 mono_domain_unlock (domain);
2697 mono_loader_unlock ();
2699 #endif /* DISABLE_REMOTING */
2703 * mono_object_get_virtual_method:
2704 * @obj: object to operate on.
2707 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2708 * the instance of a callvirt of method.
2711 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2714 MonoMethod **vtable;
2715 gboolean is_proxy = FALSE;
2716 MonoMethod *res = NULL;
2718 klass = mono_object_class (obj);
2719 #ifndef DISABLE_REMOTING
2720 if (klass == mono_defaults.transparent_proxy_class) {
2721 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2726 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2729 mono_class_setup_vtable (klass);
2730 vtable = klass->vtable;
2732 if (method->slot == -1) {
2733 /* method->slot might not be set for instances of generic methods */
2734 if (method->is_inflated) {
2735 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2736 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2739 g_assert_not_reached ();
2743 /* check method->slot is a valid index: perform isinstance? */
2744 if (method->slot != -1) {
2745 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2747 gboolean variance_used = FALSE;
2748 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2749 g_assert (iface_offset > 0);
2750 res = vtable [iface_offset + method->slot];
2753 res = vtable [method->slot];
2757 #ifndef DISABLE_REMOTING
2759 /* It may be an interface, abstract class method or generic method */
2760 if (!res || mono_method_signature (res)->generic_param_count)
2763 /* generic methods demand invoke_with_check */
2764 if (mono_method_signature (res)->generic_param_count)
2765 res = mono_marshal_get_remoting_invoke_with_check (res);
2768 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2769 res = mono_cominterop_get_invoke (res);
2772 res = mono_marshal_get_remoting_invoke (res);
2777 if (method->is_inflated) {
2778 /* Have to inflate the result */
2779 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2789 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2791 g_error ("runtime invoke called on uninitialized runtime");
2795 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2798 * mono_runtime_invoke:
2799 * @method: method to invoke
2800 * @obJ: object instance
2801 * @params: arguments to the method
2802 * @exc: exception information.
2804 * Invokes the method represented by @method on the object @obj.
2806 * obj is the 'this' pointer, it should be NULL for static
2807 * methods, a MonoObject* for object instances and a pointer to
2808 * the value type for value types.
2810 * The params array contains the arguments to the method with the
2811 * same convention: MonoObject* pointers for object instances and
2812 * pointers to the value type otherwise.
2814 * From unmanaged code you'll usually use the
2815 * mono_runtime_invoke() variant.
2817 * Note that this function doesn't handle virtual methods for
2818 * you, it will exec the exact method you pass: we still need to
2819 * expose a function to lookup the derived class implementation
2820 * of a virtual method (there are examples of this in the code,
2823 * You can pass NULL as the exc argument if you don't want to
2824 * catch exceptions, otherwise, *exc will be set to the exception
2825 * thrown, if any. if an exception is thrown, you can't use the
2826 * MonoObject* result from the function.
2828 * If the method returns a value type, it is boxed in an object
2832 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2836 if (mono_runtime_get_no_exec ())
2837 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2839 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2840 mono_profiler_method_start_invoke (method);
2842 result = default_mono_runtime_invoke (method, obj, params, exc);
2844 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2845 mono_profiler_method_end_invoke (method);
2851 * mono_method_get_unmanaged_thunk:
2852 * @method: method to generate a thunk for.
2854 * Returns an unmanaged->managed thunk that can be used to call
2855 * a managed method directly from C.
2857 * The thunk's C signature closely matches the managed signature:
2859 * C#: public bool Equals (object obj);
2860 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2861 * MonoObject*, MonoException**);
2863 * The 1st ("this") parameter must not be used with static methods:
2865 * C#: public static bool ReferenceEquals (object a, object b);
2866 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2869 * The last argument must be a non-null pointer of a MonoException* pointer.
2870 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2871 * exception has been thrown in managed code. Otherwise it will point
2872 * to the MonoException* caught by the thunk. In this case, the result of
2873 * the thunk is undefined:
2875 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2876 * MonoException *ex = NULL;
2877 * Equals func = mono_method_get_unmanaged_thunk (method);
2878 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2880 * // handle exception
2883 * The calling convention of the thunk matches the platform's default
2884 * convention. This means that under Windows, C declarations must
2885 * contain the __stdcall attribute:
2887 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2888 * MonoObject*, MonoException**);
2892 * Value type arguments and return values are treated as they were objects:
2894 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2895 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2897 * Arguments must be properly boxed upon trunk's invocation, while return
2898 * values must be unboxed.
2901 mono_method_get_unmanaged_thunk (MonoMethod *method)
2903 method = mono_marshal_get_thunk_invoke_wrapper (method);
2904 return mono_compile_method (method);
2908 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2912 /* object fields cannot be byref, so we don't need a
2914 gpointer *p = (gpointer*)dest;
2921 case MONO_TYPE_BOOLEAN:
2923 case MONO_TYPE_U1: {
2924 guint8 *p = (guint8*)dest;
2925 *p = value ? *(guint8*)value : 0;
2930 case MONO_TYPE_CHAR: {
2931 guint16 *p = (guint16*)dest;
2932 *p = value ? *(guint16*)value : 0;
2935 #if SIZEOF_VOID_P == 4
2940 case MONO_TYPE_U4: {
2941 gint32 *p = (gint32*)dest;
2942 *p = value ? *(gint32*)value : 0;
2945 #if SIZEOF_VOID_P == 8
2950 case MONO_TYPE_U8: {
2951 gint64 *p = (gint64*)dest;
2952 *p = value ? *(gint64*)value : 0;
2955 case MONO_TYPE_R4: {
2956 float *p = (float*)dest;
2957 *p = value ? *(float*)value : 0;
2960 case MONO_TYPE_R8: {
2961 double *p = (double*)dest;
2962 *p = value ? *(double*)value : 0;
2965 case MONO_TYPE_STRING:
2966 case MONO_TYPE_SZARRAY:
2967 case MONO_TYPE_CLASS:
2968 case MONO_TYPE_OBJECT:
2969 case MONO_TYPE_ARRAY:
2970 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2972 case MONO_TYPE_FNPTR:
2973 case MONO_TYPE_PTR: {
2974 gpointer *p = (gpointer*)dest;
2975 *p = deref_pointer? *(gpointer*)value: value;
2978 case MONO_TYPE_VALUETYPE:
2979 /* note that 't' and 'type->type' can be different */
2980 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2981 t = mono_class_enum_basetype (type->data.klass)->type;
2984 MonoClass *class = mono_class_from_mono_type (type);
2985 int size = mono_class_value_size (class, NULL);
2987 mono_gc_bzero_atomic (dest, size);
2989 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2992 case MONO_TYPE_GENERICINST:
2993 t = type->data.generic_class->container_class->byval_arg.type;
2996 g_error ("got type %x", type->type);
3001 * mono_field_set_value:
3002 * @obj: Instance object
3003 * @field: MonoClassField describing the field to set
3004 * @value: The value to be set
3006 * Sets the value of the field described by @field in the object instance @obj
3007 * to the value passed in @value. This method should only be used for instance
3008 * fields. For static fields, use mono_field_static_set_value.
3010 * The value must be on the native format of the field type.
3013 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3017 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3019 dest = (char*)obj + field->offset;
3020 set_value (field->type, dest, value, FALSE);
3024 * mono_field_static_set_value:
3025 * @field: MonoClassField describing the field to set
3026 * @value: The value to be set
3028 * Sets the value of the static field described by @field
3029 * to the value passed in @value.
3031 * The value must be on the native format of the field type.
3034 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3038 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3039 /* you cant set a constant! */
3040 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3042 if (field->offset == -1) {
3043 /* Special static */
3046 mono_domain_lock (vt->domain);
3047 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3048 mono_domain_unlock (vt->domain);
3049 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3051 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3053 set_value (field->type, dest, value, FALSE);
3057 * mono_vtable_get_static_field_data:
3059 * Internal use function: return a pointer to the memory holding the static fields
3060 * for a class or NULL if there are no static fields.
3061 * This is exported only for use by the debugger.
3064 mono_vtable_get_static_field_data (MonoVTable *vt)
3066 if (!vt->has_static_fields)
3068 return vt->vtable [vt->klass->vtable_size];
3072 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3076 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3077 if (field->offset == -1) {
3078 /* Special static */
3081 mono_domain_lock (vt->domain);
3082 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3083 mono_domain_unlock (vt->domain);
3084 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3086 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3089 src = (guint8*)obj + field->offset;
3096 * mono_field_get_value:
3097 * @obj: Object instance
3098 * @field: MonoClassField describing the field to fetch information from
3099 * @value: pointer to the location where the value will be stored
3101 * Use this routine to get the value of the field @field in the object
3104 * The pointer provided by value must be of the field type, for reference
3105 * types this is a MonoObject*, for value types its the actual pointer to
3110 * mono_field_get_value (obj, int_field, &i);
3113 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3119 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3121 src = (char*)obj + field->offset;
3122 set_value (field->type, value, src, TRUE);
3126 * mono_field_get_value_object:
3127 * @domain: domain where the object will be created (if boxing)
3128 * @field: MonoClassField describing the field to fetch information from
3129 * @obj: The object instance for the field.
3131 * Returns: a new MonoObject with the value from the given field. If the
3132 * field represents a value type, the value is boxed.
3136 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3140 MonoVTable *vtable = NULL;
3142 gboolean is_static = FALSE;
3143 gboolean is_ref = FALSE;
3144 gboolean is_literal = FALSE;
3145 gboolean is_ptr = FALSE;
3147 MonoType *type = mono_field_get_type_checked (field, &error);
3149 if (!mono_error_ok (&error))
3150 mono_error_raise_exception (&error);
3152 switch (type->type) {
3153 case MONO_TYPE_STRING:
3154 case MONO_TYPE_OBJECT:
3155 case MONO_TYPE_CLASS:
3156 case MONO_TYPE_ARRAY:
3157 case MONO_TYPE_SZARRAY:
3162 case MONO_TYPE_BOOLEAN:
3165 case MONO_TYPE_CHAR:
3174 case MONO_TYPE_VALUETYPE:
3175 is_ref = type->byref;
3177 case MONO_TYPE_GENERICINST:
3178 is_ref = !mono_type_generic_inst_is_valuetype (type);
3184 g_error ("type 0x%x not handled in "
3185 "mono_field_get_value_object", type->type);
3189 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3192 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3196 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3197 if (!vtable->initialized)
3198 mono_runtime_class_init (vtable);
3206 get_default_field_value (domain, field, &o);
3207 } else if (is_static) {
3208 mono_field_static_get_value (vtable, field, &o);
3210 mono_field_get_value (obj, field, &o);
3216 static MonoMethod *m;
3222 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3223 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3229 get_default_field_value (domain, field, v);
3230 } else if (is_static) {
3231 mono_field_static_get_value (vtable, field, v);
3233 mono_field_get_value (obj, field, v);
3236 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3238 args [1] = mono_type_get_object (mono_domain_get (), type);
3240 return mono_runtime_invoke (m, NULL, args, NULL);
3243 /* boxed value type */
3244 klass = mono_class_from_mono_type (type);
3246 if (mono_class_is_nullable (klass))
3247 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3249 o = mono_object_new (domain, klass);
3250 v = ((gchar *) o) + sizeof (MonoObject);
3253 get_default_field_value (domain, field, v);
3254 } else if (is_static) {
3255 mono_field_static_get_value (vtable, field, v);
3257 mono_field_get_value (obj, field, v);
3264 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3267 const char *p = blob;
3268 mono_metadata_decode_blob_size (p, &p);
3271 case MONO_TYPE_BOOLEAN:
3274 *(guint8 *) value = *p;
3276 case MONO_TYPE_CHAR:
3279 *(guint16*) value = read16 (p);
3283 *(guint32*) value = read32 (p);
3287 *(guint64*) value = read64 (p);
3290 readr4 (p, (float*) value);
3293 readr8 (p, (double*) value);
3295 case MONO_TYPE_STRING:
3296 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3298 case MONO_TYPE_CLASS:
3299 *(gpointer*) value = NULL;
3303 g_warning ("type 0x%02x should not be in constant table", type);
3309 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3311 MonoTypeEnum def_type;
3314 data = mono_class_get_field_default_value (field, &def_type);
3315 mono_get_constant_value_from_blob (domain, def_type, data, value);
3319 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3323 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3325 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3326 get_default_field_value (vt->domain, field, value);
3330 if (field->offset == -1) {
3331 /* Special static */
3332 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3333 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3335 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3337 set_value (field->type, value, src, TRUE);
3341 * mono_field_static_get_value:
3342 * @vt: vtable to the object
3343 * @field: MonoClassField describing the field to fetch information from
3344 * @value: where the value is returned
3346 * Use this routine to get the value of the static field @field value.
3348 * The pointer provided by value must be of the field type, for reference
3349 * types this is a MonoObject*, for value types its the actual pointer to
3354 * mono_field_static_get_value (vt, int_field, &i);
3357 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3359 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3363 * mono_property_set_value:
3364 * @prop: MonoProperty to set
3365 * @obj: instance object on which to act
3366 * @params: parameters to pass to the propery
3367 * @exc: optional exception
3369 * Invokes the property's set method with the given arguments on the
3370 * object instance obj (or NULL for static properties).
3372 * You can pass NULL as the exc argument if you don't want to
3373 * catch exceptions, otherwise, *exc will be set to the exception
3374 * thrown, if any. if an exception is thrown, you can't use the
3375 * MonoObject* result from the function.
3378 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3380 default_mono_runtime_invoke (prop->set, obj, params, exc);
3384 * mono_property_get_value:
3385 * @prop: MonoProperty to fetch
3386 * @obj: instance object on which to act
3387 * @params: parameters to pass to the propery
3388 * @exc: optional exception
3390 * Invokes the property's get method with the given arguments on the
3391 * object instance obj (or NULL for static properties).
3393 * You can pass NULL as the exc argument if you don't want to
3394 * catch exceptions, otherwise, *exc will be set to the exception
3395 * thrown, if any. if an exception is thrown, you can't use the
3396 * MonoObject* result from the function.
3398 * Returns: the value from invoking the get method on the property.
3401 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3403 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3407 * mono_nullable_init:
3408 * @buf: The nullable structure to initialize.
3409 * @value: the value to initialize from
3410 * @klass: the type for the object
3412 * Initialize the nullable structure pointed to by @buf from @value which
3413 * should be a boxed value type. The size of @buf should be able to hold
3414 * as much data as the @klass->instance_size (which is the number of bytes
3415 * that will be copies).
3417 * Since Nullables have variable structure, we can not define a C
3418 * structure for them.
3421 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3423 MonoClass *param_class = klass->cast_class;
3425 mono_class_setup_fields_locking (klass);
3426 g_assert (klass->fields_inited);
3428 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3429 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3431 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3433 if (param_class->has_references)
3434 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3436 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3438 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3443 * mono_nullable_box:
3444 * @buf: The buffer representing the data to be boxed
3445 * @klass: the type to box it as.
3447 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3451 mono_nullable_box (guint8 *buf, MonoClass *klass)
3453 MonoClass *param_class = klass->cast_class;
3455 mono_class_setup_fields_locking (klass);
3456 g_assert (klass->fields_inited);
3458 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3459 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3461 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3462 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3463 if (param_class->has_references)
3464 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3466 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3474 * mono_get_delegate_invoke:
3475 * @klass: The delegate class
3477 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3480 mono_get_delegate_invoke (MonoClass *klass)
3484 /* This is called at runtime, so avoid the slower search in metadata */
3485 mono_class_setup_methods (klass);
3486 if (klass->exception_type)
3488 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3493 * mono_get_delegate_begin_invoke:
3494 * @klass: The delegate class
3496 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3499 mono_get_delegate_begin_invoke (MonoClass *klass)
3503 /* This is called at runtime, so avoid the slower search in metadata */
3504 mono_class_setup_methods (klass);
3505 if (klass->exception_type)
3507 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3512 * mono_get_delegate_end_invoke:
3513 * @klass: The delegate class
3515 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3518 mono_get_delegate_end_invoke (MonoClass *klass)
3522 /* This is called at runtime, so avoid the slower search in metadata */
3523 mono_class_setup_methods (klass);
3524 if (klass->exception_type)
3526 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3531 * mono_runtime_delegate_invoke:
3532 * @delegate: pointer to a delegate object.
3533 * @params: parameters for the delegate.
3534 * @exc: Pointer to the exception result.
3536 * Invokes the delegate method @delegate with the parameters provided.
3538 * You can pass NULL as the exc argument if you don't want to
3539 * catch exceptions, otherwise, *exc will be set to the exception
3540 * thrown, if any. if an exception is thrown, you can't use the
3541 * MonoObject* result from the function.
3544 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3547 MonoClass *klass = delegate->vtable->klass;
3549 im = mono_get_delegate_invoke (klass);
3551 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3553 return mono_runtime_invoke (im, delegate, params, exc);
3556 static char **main_args = NULL;
3557 static int num_main_args = 0;
3560 * mono_runtime_get_main_args:
3562 * Returns: a MonoArray with the arguments passed to the main program
3565 mono_runtime_get_main_args (void)
3569 MonoDomain *domain = mono_domain_get ();
3571 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3573 for (i = 0; i < num_main_args; ++i)
3574 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3580 free_main_args (void)
3584 for (i = 0; i < num_main_args; ++i)
3585 g_free (main_args [i]);
3592 * mono_runtime_set_main_args:
3593 * @argc: number of arguments from the command line
3594 * @argv: array of strings from the command line
3596 * Set the command line arguments from an embedding application that doesn't otherwise call
3597 * mono_runtime_run_main ().
3600 mono_runtime_set_main_args (int argc, char* argv[])
3605 main_args = g_new0 (char*, argc);
3606 num_main_args = argc;
3608 for (i = 0; i < argc; ++i) {
3611 utf8_arg = mono_utf8_from_external (argv[i]);
3612 if (utf8_arg == NULL) {
3613 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3614 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3618 main_args [i] = utf8_arg;
3625 * mono_runtime_run_main:
3626 * @method: the method to start the application with (usually Main)
3627 * @argc: number of arguments from the command line
3628 * @argv: array of strings from the command line
3629 * @exc: excetption results
3631 * Execute a standard Main() method (argc/argv contains the
3632 * executable name). This method also sets the command line argument value
3633 * needed by System.Environment.
3638 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3642 MonoArray *args = NULL;
3643 MonoDomain *domain = mono_domain_get ();
3644 gchar *utf8_fullpath;
3645 MonoMethodSignature *sig;
3647 g_assert (method != NULL);
3649 mono_thread_set_main (mono_thread_current ());
3651 main_args = g_new0 (char*, argc);
3652 num_main_args = argc;
3654 if (!g_path_is_absolute (argv [0])) {
3655 gchar *basename = g_path_get_basename (argv [0]);
3656 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3660 utf8_fullpath = mono_utf8_from_external (fullpath);
3661 if(utf8_fullpath == NULL) {
3662 /* Printing the arg text will cause glib to
3663 * whinge about "Invalid UTF-8", but at least
3664 * its relevant, and shows the problem text
3667 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3668 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3675 utf8_fullpath = mono_utf8_from_external (argv[0]);
3676 if(utf8_fullpath == NULL) {
3677 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3678 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3683 main_args [0] = utf8_fullpath;
3685 for (i = 1; i < argc; ++i) {
3688 utf8_arg=mono_utf8_from_external (argv[i]);
3689 if(utf8_arg==NULL) {
3690 /* Ditto the comment about Invalid UTF-8 here */
3691 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3692 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3696 main_args [i] = utf8_arg;
3701 sig = mono_method_signature (method);
3703 g_print ("Unable to load Main method.\n");
3707 if (sig->param_count) {
3708 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3709 for (i = 0; i < argc; ++i) {
3710 /* The encodings should all work, given that
3711 * we've checked all these args for the
3714 gchar *str = mono_utf8_from_external (argv [i]);
3715 MonoString *arg = mono_string_new (domain, str);
3716 mono_array_setref (args, i, arg);
3720 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3723 mono_assembly_set_main (method->klass->image->assembly);
3725 return mono_runtime_exec_main (method, args, exc);
3729 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3731 static MonoMethod *serialize_method;
3736 if (!serialize_method) {
3737 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3738 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3741 if (!serialize_method) {
3746 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3750 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3758 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3760 static MonoMethod *deserialize_method;
3765 if (!deserialize_method) {
3766 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3767 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3769 if (!deserialize_method) {
3776 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3783 #ifndef DISABLE_REMOTING
3785 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3787 static MonoMethod *get_proxy_method;
3789 MonoDomain *domain = mono_domain_get ();
3790 MonoRealProxy *real_proxy;
3791 MonoReflectionType *reflection_type;
3792 MonoTransparentProxy *transparent_proxy;
3794 if (!get_proxy_method)
3795 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3797 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3799 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3800 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3802 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3803 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3806 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3810 return (MonoObject*) transparent_proxy;
3812 #endif /* DISABLE_REMOTING */
3815 * mono_object_xdomain_representation
3817 * @target_domain: a domain
3818 * @exc: pointer to a MonoObject*
3820 * Creates a representation of obj in the domain target_domain. This
3821 * is either a copy of obj arrived through via serialization and
3822 * deserialization or a proxy, depending on whether the object is
3823 * serializable or marshal by ref. obj must not be in target_domain.
3825 * If the object cannot be represented in target_domain, NULL is
3826 * returned and *exc is set to an appropriate exception.
3829 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3831 MonoObject *deserialized = NULL;
3832 gboolean failure = FALSE;
3836 #ifndef DISABLE_REMOTING
3837 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3838 deserialized = make_transparent_proxy (obj, &failure, exc);
3843 MonoDomain *domain = mono_domain_get ();
3844 MonoObject *serialized;
3846 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3847 serialized = serialize_object (obj, &failure, exc);
3848 mono_domain_set_internal_with_options (target_domain, FALSE);
3850 deserialized = deserialize_object (serialized, &failure, exc);
3851 if (domain != target_domain)
3852 mono_domain_set_internal_with_options (domain, FALSE);
3855 return deserialized;
3858 /* Used in call_unhandled_exception_delegate */
3860 create_unhandled_exception_eventargs (MonoObject *exc)
3864 MonoMethod *method = NULL;
3865 MonoBoolean is_terminating = TRUE;
3868 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3871 mono_class_init (klass);
3873 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3874 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3878 args [1] = &is_terminating;
3880 obj = mono_object_new (mono_domain_get (), klass);
3881 mono_runtime_invoke (method, obj, args, NULL);
3886 /* Used in mono_unhandled_exception */
3888 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3889 MonoObject *e = NULL;
3891 MonoDomain *current_domain = mono_domain_get ();
3893 if (domain != current_domain)
3894 mono_domain_set_internal_with_options (domain, FALSE);
3896 g_assert (domain == mono_object_domain (domain->domain));
3898 if (mono_object_domain (exc) != domain) {
3899 MonoObject *serialization_exc;
3901 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3903 if (serialization_exc) {
3905 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3908 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3909 "System.Runtime.Serialization", "SerializationException",
3910 "Could not serialize unhandled exception.");
3914 g_assert (mono_object_domain (exc) == domain);
3916 pa [0] = domain->domain;
3917 pa [1] = create_unhandled_exception_eventargs (exc);
3918 mono_runtime_delegate_invoke (delegate, pa, &e);
3920 if (domain != current_domain)
3921 mono_domain_set_internal_with_options (current_domain, FALSE);
3925 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3926 if (!mono_error_ok (&error)) {
3927 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3928 mono_error_cleanup (&error);
3930 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3936 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3939 * mono_runtime_unhandled_exception_policy_set:
3940 * @policy: the new policy
3942 * This is a VM internal routine.
3944 * Sets the runtime policy for handling unhandled exceptions.
3947 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3948 runtime_unhandled_exception_policy = policy;
3952 * mono_runtime_unhandled_exception_policy_get:
3954 * This is a VM internal routine.
3956 * Gets the runtime policy for handling unhandled exceptions.
3958 MonoRuntimeUnhandledExceptionPolicy
3959 mono_runtime_unhandled_exception_policy_get (void) {
3960 return runtime_unhandled_exception_policy;
3964 * mono_unhandled_exception:
3965 * @exc: exception thrown
3967 * This is a VM internal routine.
3969 * We call this function when we detect an unhandled exception
3970 * in the default domain.
3972 * It invokes the * UnhandledException event in AppDomain or prints
3973 * a warning to the console
3976 mono_unhandled_exception (MonoObject *exc)
3978 MonoDomain *current_domain = mono_domain_get ();
3979 MonoDomain *root_domain = mono_get_root_domain ();
3980 MonoClassField *field;
3981 MonoObject *current_appdomain_delegate;
3982 MonoObject *root_appdomain_delegate;
3984 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3985 "UnhandledException");
3988 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3989 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3990 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3991 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3992 if (current_domain != root_domain) {
3993 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3995 current_appdomain_delegate = NULL;
3998 /* set exitcode only if we will abort the process */
3999 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4001 mono_environment_exitcode_set (1);
4002 mono_print_unhandled_exception (exc);
4004 if (root_appdomain_delegate) {
4005 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4007 if (current_appdomain_delegate) {
4008 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4015 * mono_runtime_exec_managed_code:
4016 * @domain: Application domain
4017 * @main_func: function to invoke from the execution thread
4018 * @main_args: parameter to the main_func
4020 * Launch a new thread to execute a function
4022 * main_func is called back from the thread with main_args as the
4023 * parameter. The callback function is expected to start Main()
4024 * eventually. This function then waits for all managed threads to
4026 * It is not necesseray anymore to execute managed code in a subthread,
4027 * so this function should not be used anymore by default: just
4028 * execute the code and then call mono_thread_manage ().
4031 mono_runtime_exec_managed_code (MonoDomain *domain,
4032 MonoMainThreadFunc main_func,
4035 mono_thread_create (domain, main_func, main_args);
4037 mono_thread_manage ();
4041 * Execute a standard Main() method (args doesn't contain the
4045 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4050 MonoCustomAttrInfo* cinfo;
4051 gboolean has_stathread_attribute;
4052 MonoInternalThread* thread = mono_thread_internal_current ();
4058 domain = mono_object_domain (args);
4059 if (!domain->entry_assembly) {
4061 MonoAssembly *assembly;
4063 assembly = method->klass->image->assembly;
4064 domain->entry_assembly = assembly;
4065 /* Domains created from another domain already have application_base and configuration_file set */
4066 if (domain->setup->application_base == NULL) {
4067 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4070 if (domain->setup->configuration_file == NULL) {
4071 str = g_strconcat (assembly->image->name, ".config", NULL);
4072 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4074 mono_set_private_bin_path_from_config (domain);
4078 cinfo = mono_custom_attrs_from_method (method);
4080 static MonoClass *stathread_attribute = NULL;
4081 if (!stathread_attribute)
4082 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4083 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4085 mono_custom_attrs_free (cinfo);
4087 has_stathread_attribute = FALSE;
4089 if (has_stathread_attribute) {
4090 thread->apartment_state = ThreadApartmentState_STA;
4092 thread->apartment_state = ThreadApartmentState_MTA;
4094 mono_thread_init_apartment_state ();
4096 /* FIXME: check signature of method */
4097 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4099 res = mono_runtime_invoke (method, NULL, pa, exc);
4101 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4105 mono_environment_exitcode_set (rval);
4107 mono_runtime_invoke (method, NULL, pa, exc);
4111 /* If the return type of Main is void, only
4112 * set the exitcode if an exception was thrown
4113 * (we don't want to blow away an
4114 * explicitly-set exit code)
4117 mono_environment_exitcode_set (rval);
4125 * mono_install_runtime_invoke:
4126 * @func: Function to install
4128 * This is a VM internal routine
4131 mono_install_runtime_invoke (MonoInvokeFunc func)
4133 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4138 * mono_runtime_invoke_array:
4139 * @method: method to invoke
4140 * @obJ: object instance
4141 * @params: arguments to the method
4142 * @exc: exception information.
4144 * Invokes the method represented by @method on the object @obj.
4146 * obj is the 'this' pointer, it should be NULL for static
4147 * methods, a MonoObject* for object instances and a pointer to
4148 * the value type for value types.
4150 * The params array contains the arguments to the method with the
4151 * same convention: MonoObject* pointers for object instances and
4152 * pointers to the value type otherwise. The _invoke_array
4153 * variant takes a C# object[] as the params argument (MonoArray
4154 * *params): in this case the value types are boxed inside the
4155 * respective reference representation.
4157 * From unmanaged code you'll usually use the
4158 * mono_runtime_invoke() variant.
4160 * Note that this function doesn't handle virtual methods for
4161 * you, it will exec the exact method you pass: we still need to
4162 * expose a function to lookup the derived class implementation
4163 * of a virtual method (there are examples of this in the code,
4166 * You can pass NULL as the exc argument if you don't want to
4167 * catch exceptions, otherwise, *exc will be set to the exception
4168 * thrown, if any. if an exception is thrown, you can't use the
4169 * MonoObject* result from the function.
4171 * If the method returns a value type, it is boxed in an object
4175 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4178 MonoMethodSignature *sig = mono_method_signature (method);
4179 gpointer *pa = NULL;
4182 gboolean has_byref_nullables = FALSE;
4184 if (NULL != params) {
4185 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4186 for (i = 0; i < mono_array_length (params); i++) {
4187 MonoType *t = sig->params [i];
4193 case MONO_TYPE_BOOLEAN:
4196 case MONO_TYPE_CHAR:
4205 case MONO_TYPE_VALUETYPE:
4206 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4207 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4208 pa [i] = mono_array_get (params, MonoObject*, i);
4210 has_byref_nullables = TRUE;
4212 /* MS seems to create the objects if a null is passed in */
4213 if (!mono_array_get (params, MonoObject*, i))
4214 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4218 * We can't pass the unboxed vtype byref to the callee, since
4219 * that would mean the callee would be able to modify boxed
4220 * primitive types. So we (and MS) make a copy of the boxed
4221 * object, pass that to the callee, and replace the original
4222 * boxed object in the arg array with the copy.
4224 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4225 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4226 mono_array_setref (params, i, copy);
4229 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4232 case MONO_TYPE_STRING:
4233 case MONO_TYPE_OBJECT:
4234 case MONO_TYPE_CLASS:
4235 case MONO_TYPE_ARRAY:
4236 case MONO_TYPE_SZARRAY:
4238 pa [i] = mono_array_addr (params, MonoObject*, i);
4239 // FIXME: I need to check this code path
4241 pa [i] = mono_array_get (params, MonoObject*, i);
4243 case MONO_TYPE_GENERICINST:
4245 t = &t->data.generic_class->container_class->this_arg;
4247 t = &t->data.generic_class->container_class->byval_arg;
4249 case MONO_TYPE_PTR: {
4252 /* The argument should be an IntPtr */
4253 arg = mono_array_get (params, MonoObject*, i);
4257 g_assert (arg->vtable->klass == mono_defaults.int_class);
4258 pa [i] = ((MonoIntPtr*)arg)->m_value;
4263 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4268 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4271 if (mono_class_is_nullable (method->klass)) {
4272 /* Need to create a boxed vtype instead */
4278 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4282 obj = mono_object_new (mono_domain_get (), method->klass);
4283 g_assert (obj); /*maybe we should raise a TLE instead?*/
4284 #ifndef DISABLE_REMOTING
4285 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4286 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4289 if (method->klass->valuetype)
4290 o = mono_object_unbox (obj);
4293 } else if (method->klass->valuetype) {
4294 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4297 mono_runtime_invoke (method, o, pa, exc);
4300 if (mono_class_is_nullable (method->klass)) {
4301 MonoObject *nullable;
4303 /* Convert the unboxed vtype into a Nullable structure */
4304 nullable = mono_object_new (mono_domain_get (), method->klass);
4306 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4307 obj = mono_object_unbox (nullable);
4310 /* obj must be already unboxed if needed */
4311 res = mono_runtime_invoke (method, obj, pa, exc);
4313 if (sig->ret->type == MONO_TYPE_PTR) {
4314 MonoClass *pointer_class;
4315 static MonoMethod *box_method;
4317 MonoObject *box_exc;
4320 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4321 * convert it to a Pointer object.
4323 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4325 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4327 g_assert (res->vtable->klass == mono_defaults.int_class);
4328 box_args [0] = ((MonoIntPtr*)res)->m_value;
4329 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4330 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4331 g_assert (!box_exc);
4334 if (has_byref_nullables) {
4336 * The runtime invoke wrapper already converted byref nullables back,
4337 * and stored them in pa, we just need to copy them back to the
4340 for (i = 0; i < mono_array_length (params); i++) {
4341 MonoType *t = sig->params [i];
4343 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4344 mono_array_setref (params, i, pa [i]);
4353 arith_overflow (void)
4355 mono_raise_exception (mono_get_exception_overflow ());
4359 * mono_object_allocate:
4360 * @size: number of bytes to allocate
4362 * This is a very simplistic routine until we have our GC-aware
4365 * Returns: an allocated object of size @size, or NULL on failure.
4367 static inline void *
4368 mono_object_allocate (size_t size, MonoVTable *vtable)
4371 mono_stats.new_object_count++;
4372 ALLOC_OBJECT (o, vtable, size);
4378 * mono_object_allocate_ptrfree:
4379 * @size: number of bytes to allocate
4381 * Note that the memory allocated is not zeroed.
4382 * Returns: an allocated object of size @size, or NULL on failure.
4384 static inline void *
4385 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4388 mono_stats.new_object_count++;
4389 ALLOC_PTRFREE (o, vtable, size);
4393 static inline void *
4394 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4397 ALLOC_TYPED (o, size, vtable);
4398 mono_stats.new_object_count++;
4405 * @klass: the class of the object that we want to create
4407 * Returns: a newly created object whose definition is
4408 * looked up using @klass. This will not invoke any constructors,
4409 * so the consumer of this routine has to invoke any constructors on
4410 * its own to initialize the object.
4412 * It returns NULL on failure.
4415 mono_object_new (MonoDomain *domain, MonoClass *klass)
4419 MONO_ARCH_SAVE_REGS;
4420 vtable = mono_class_vtable (domain, klass);
4423 return mono_object_new_specific (vtable);
4427 * mono_object_new_pinned:
4429 * Same as mono_object_new, but the returned object will be pinned.
4430 * For SGEN, these objects will only be freed at appdomain unload.
4433 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4437 MONO_ARCH_SAVE_REGS;
4438 vtable = mono_class_vtable (domain, klass);
4443 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4445 return mono_object_new_specific (vtable);
4450 * mono_object_new_specific:
4451 * @vtable: the vtable of the object that we want to create
4453 * Returns: A newly created object with class and domain specified
4457 mono_object_new_specific (MonoVTable *vtable)
4461 MONO_ARCH_SAVE_REGS;
4463 /* check for is_com_object for COM Interop */
4464 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4467 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4470 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4473 mono_class_init (klass);
4475 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4477 vtable->domain->create_proxy_for_type_method = im;
4480 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4482 o = mono_runtime_invoke (im, NULL, pa, NULL);
4483 if (o != NULL) return o;
4486 return mono_object_new_alloc_specific (vtable);
4490 mono_object_new_alloc_specific (MonoVTable *vtable)
4494 if (!vtable->klass->has_references) {
4495 o = mono_object_new_ptrfree (vtable);
4496 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4497 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4499 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4500 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4502 if (G_UNLIKELY (vtable->klass->has_finalize))
4503 mono_object_register_finalizer (o);
4505 if (G_UNLIKELY (profile_allocs))
4506 mono_profiler_allocation (o, vtable->klass);
4511 mono_object_new_fast (MonoVTable *vtable)
4514 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4519 mono_object_new_ptrfree (MonoVTable *vtable)
4522 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4523 #if NEED_TO_ZERO_PTRFREE
4524 /* an inline memset is much faster for the common vcase of small objects
4525 * note we assume the allocated size is a multiple of sizeof (void*).
4527 if (vtable->klass->instance_size < 128) {
4529 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4530 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4536 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4543 mono_object_new_ptrfree_box (MonoVTable *vtable)
4546 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4547 /* the object will be boxed right away, no need to memzero it */
4552 * mono_class_get_allocation_ftn:
4554 * @for_box: the object will be used for boxing
4555 * @pass_size_in_words:
4557 * Return the allocation function appropriate for the given class.
4561 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4563 *pass_size_in_words = FALSE;
4565 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4566 profile_allocs = FALSE;
4568 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4569 return mono_object_new_specific;
4571 if (!vtable->klass->has_references) {
4572 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4574 return mono_object_new_ptrfree_box;
4575 return mono_object_new_ptrfree;
4578 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4580 return mono_object_new_fast;
4583 * FIXME: This is actually slower than mono_object_new_fast, because
4584 * of the overhead of parameter passing.
4587 *pass_size_in_words = TRUE;
4588 #ifdef GC_REDIRECT_TO_LOCAL
4589 return GC_local_gcj_fast_malloc;
4591 return GC_gcj_fast_malloc;
4596 return mono_object_new_specific;
4600 * mono_object_new_from_token:
4601 * @image: Context where the type_token is hosted
4602 * @token: a token of the type that we want to create
4604 * Returns: A newly created object whose definition is
4605 * looked up using @token in the @image image
4608 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4613 class = mono_class_get_checked (image, token, &error);
4614 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4616 return mono_object_new (domain, class);
4621 * mono_object_clone:
4622 * @obj: the object to clone
4624 * Returns: A newly created object who is a shallow copy of @obj
4627 mono_object_clone (MonoObject *obj)
4630 int size = obj->vtable->klass->instance_size;
4632 if (obj->vtable->klass->rank)
4633 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4635 o = mono_object_allocate (size, obj->vtable);
4637 if (obj->vtable->klass->has_references) {
4638 mono_gc_wbarrier_object_copy (o, obj);
4640 int size = obj->vtable->klass->instance_size;
4641 /* do not copy the sync state */
4642 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4644 if (G_UNLIKELY (profile_allocs))
4645 mono_profiler_allocation (o, obj->vtable->klass);
4647 if (obj->vtable->klass->has_finalize)
4648 mono_object_register_finalizer (o);
4653 * mono_array_full_copy:
4654 * @src: source array to copy
4655 * @dest: destination array
4657 * Copies the content of one array to another with exactly the same type and size.
4660 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4663 MonoClass *klass = src->obj.vtable->klass;
4665 MONO_ARCH_SAVE_REGS;
4667 g_assert (klass == dest->obj.vtable->klass);
4669 size = mono_array_length (src);
4670 g_assert (size == mono_array_length (dest));
4671 size *= mono_array_element_size (klass);
4673 if (klass->element_class->valuetype) {
4674 if (klass->element_class->has_references)
4675 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4677 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4679 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4682 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4687 * mono_array_clone_in_domain:
4688 * @domain: the domain in which the array will be cloned into
4689 * @array: the array to clone
4691 * This routine returns a copy of the array that is hosted on the
4692 * specified MonoDomain.
4695 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4700 MonoClass *klass = array->obj.vtable->klass;
4702 MONO_ARCH_SAVE_REGS;
4704 if (array->bounds == NULL) {
4705 size = mono_array_length (array);
4706 o = mono_array_new_full (domain, klass, &size, NULL);
4708 size *= mono_array_element_size (klass);
4710 if (klass->element_class->valuetype) {
4711 if (klass->element_class->has_references)
4712 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4714 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4716 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4719 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4724 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4725 size = mono_array_element_size (klass);
4726 for (i = 0; i < klass->rank; ++i) {
4727 sizes [i] = array->bounds [i].length;
4728 size *= array->bounds [i].length;
4729 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4731 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4733 if (klass->element_class->valuetype) {
4734 if (klass->element_class->has_references)
4735 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4737 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4739 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4742 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4750 * @array: the array to clone
4752 * Returns: A newly created array who is a shallow copy of @array
4755 mono_array_clone (MonoArray *array)
4757 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4760 /* helper macros to check for overflow when calculating the size of arrays */
4761 #ifdef MONO_BIG_ARRAYS
4762 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4763 #define MYGUINT_MAX MYGUINT64_MAX
4764 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4765 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4766 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4767 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4768 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4770 #define MYGUINT32_MAX 4294967295U
4771 #define MYGUINT_MAX MYGUINT32_MAX
4772 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4773 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4774 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4775 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4776 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4780 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4784 byte_len = mono_array_element_size (class);
4785 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4788 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4790 byte_len += sizeof (MonoArray);
4798 * mono_array_new_full:
4799 * @domain: domain where the object is created
4800 * @array_class: array class
4801 * @lengths: lengths for each dimension in the array
4802 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4804 * This routine creates a new array objects with the given dimensions,
4805 * lower bounds and type.
4808 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4810 uintptr_t byte_len = 0, len, bounds_size;
4813 MonoArrayBounds *bounds;
4817 if (!array_class->inited)
4818 mono_class_init (array_class);
4822 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4823 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4825 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4829 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4831 for (i = 0; i < array_class->rank; ++i) {
4832 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4834 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4835 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4840 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4841 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4845 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4846 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4847 byte_len = (byte_len + 3) & ~3;
4848 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4849 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4850 byte_len += bounds_size;
4853 * Following three lines almost taken from mono_object_new ():
4854 * they need to be kept in sync.
4856 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4857 #ifndef HAVE_SGEN_GC
4858 if (!array_class->has_references) {
4859 o = mono_object_allocate_ptrfree (byte_len, vtable);
4860 #if NEED_TO_ZERO_PTRFREE
4861 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4863 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4864 o = mono_object_allocate_spec (byte_len, vtable);
4866 o = mono_object_allocate (byte_len, vtable);
4869 array = (MonoArray*)o;
4870 array->max_length = len;
4873 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4874 array->bounds = bounds;
4878 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4880 o = mono_gc_alloc_vector (vtable, byte_len, len);
4881 array = (MonoArray*)o;
4882 mono_stats.new_object_count++;
4884 bounds = array->bounds;
4888 for (i = 0; i < array_class->rank; ++i) {
4889 bounds [i].length = lengths [i];
4891 bounds [i].lower_bound = lower_bounds [i];
4895 if (G_UNLIKELY (profile_allocs))
4896 mono_profiler_allocation (o, array_class);
4903 * @domain: domain where the object is created
4904 * @eclass: element class
4905 * @n: number of array elements
4907 * This routine creates a new szarray with @n elements of type @eclass.
4910 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4914 MONO_ARCH_SAVE_REGS;
4916 ac = mono_array_class_get (eclass, 1);
4919 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4923 * mono_array_new_specific:
4924 * @vtable: a vtable in the appropriate domain for an initialized class
4925 * @n: number of array elements
4927 * This routine is a fast alternative to mono_array_new() for code which
4928 * can be sure about the domain it operates in.
4931 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4937 MONO_ARCH_SAVE_REGS;
4939 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4944 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4945 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4948 #ifndef HAVE_SGEN_GC
4949 if (!vtable->klass->has_references) {
4950 o = mono_object_allocate_ptrfree (byte_len, vtable);
4951 #if NEED_TO_ZERO_PTRFREE
4952 ((MonoArray*)o)->bounds = NULL;
4953 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4955 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4956 o = mono_object_allocate_spec (byte_len, vtable);
4958 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4959 o = mono_object_allocate (byte_len, vtable);
4962 ao = (MonoArray *)o;
4965 o = mono_gc_alloc_vector (vtable, byte_len, n);
4967 mono_stats.new_object_count++;
4970 if (G_UNLIKELY (profile_allocs))
4971 mono_profiler_allocation (o, vtable->klass);
4977 * mono_string_new_utf16:
4978 * @text: a pointer to an utf16 string
4979 * @len: the length of the string
4981 * Returns: A newly created string object which contains @text.
4984 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4988 s = mono_string_new_size (domain, len);
4989 g_assert (s != NULL);
4991 memcpy (mono_string_chars (s), text, len * 2);
4997 * mono_string_new_utf32:
4998 * @text: a pointer to an utf32 string
4999 * @len: the length of the string
5001 * Returns: A newly created string object which contains @text.
5004 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5007 mono_unichar2 *utf16_output = NULL;
5008 gint32 utf16_len = 0;
5009 GError *error = NULL;
5010 glong items_written;
5012 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5015 g_error_free (error);
5017 while (utf16_output [utf16_len]) utf16_len++;
5019 s = mono_string_new_size (domain, utf16_len);
5020 g_assert (s != NULL);
5022 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5024 g_free (utf16_output);
5030 * mono_string_new_size:
5031 * @text: a pointer to an utf16 string
5032 * @len: the length of the string
5034 * Returns: A newly created string object of @len
5037 mono_string_new_size (MonoDomain *domain, gint32 len)
5043 /* check for overflow */
5044 if (len < 0 || len > ((SIZE_MAX - sizeof (MonoString) - 2) / 2))
5045 mono_gc_out_of_memory (-1);
5047 size = (sizeof (MonoString) + ((len + 1) * 2));
5048 g_assert (size > 0);
5050 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5053 #ifndef HAVE_SGEN_GC
5054 s = mono_object_allocate_ptrfree (size, vtable);
5058 s = mono_gc_alloc_string (vtable, size, len);
5060 #if NEED_TO_ZERO_PTRFREE
5063 if (G_UNLIKELY (profile_allocs))
5064 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5070 * mono_string_new_len:
5071 * @text: a pointer to an utf8 string
5072 * @length: number of bytes in @text to consider
5074 * Returns: A newly created string object which contains @text.
5077 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5079 GError *error = NULL;
5080 MonoString *o = NULL;
5082 glong items_written;
5084 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5087 o = mono_string_new_utf16 (domain, ut, items_written);
5089 g_error_free (error);
5098 * @text: a pointer to an utf8 string
5100 * Returns: A newly created string object which contains @text.
5103 mono_string_new (MonoDomain *domain, const char *text)
5105 GError *error = NULL;
5106 MonoString *o = NULL;
5108 glong items_written;
5113 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5116 o = mono_string_new_utf16 (domain, ut, items_written);
5118 g_error_free (error);
5121 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5126 MonoString *o = NULL;
5128 if (!g_utf8_validate (text, -1, &end))
5131 len = g_utf8_strlen (text, -1);
5132 o = mono_string_new_size (domain, len);
5133 str = mono_string_chars (o);
5135 while (text < end) {
5136 *str++ = g_utf8_get_char (text);
5137 text = g_utf8_next_char (text);
5144 * mono_string_new_wrapper:
5145 * @text: pointer to utf8 characters.
5147 * Helper function to create a string object from @text in the current domain.
5150 mono_string_new_wrapper (const char *text)
5152 MonoDomain *domain = mono_domain_get ();
5154 MONO_ARCH_SAVE_REGS;
5157 return mono_string_new (domain, text);
5164 * @class: the class of the value
5165 * @value: a pointer to the unboxed data
5167 * Returns: A newly created object which contains @value.
5170 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5176 g_assert (class->valuetype);
5177 if (mono_class_is_nullable (class))
5178 return mono_nullable_box (value, class);
5180 vtable = mono_class_vtable (domain, class);
5183 size = mono_class_instance_size (class);
5184 res = mono_object_new_alloc_specific (vtable);
5185 if (G_UNLIKELY (profile_allocs))
5186 mono_profiler_allocation (res, class);
5188 size = size - sizeof (MonoObject);
5191 g_assert (size == mono_class_value_size (class, NULL));
5192 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5194 #if NO_UNALIGNED_ACCESS
5195 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5199 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5202 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5205 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5208 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5211 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5215 if (class->has_finalize)
5216 mono_object_register_finalizer (res);
5222 * @dest: destination pointer
5223 * @src: source pointer
5224 * @klass: a valuetype class
5226 * Copy a valuetype from @src to @dest. This function must be used
5227 * when @klass contains references fields.
5230 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5232 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5236 * mono_value_copy_array:
5237 * @dest: destination array
5238 * @dest_idx: index in the @dest array
5239 * @src: source pointer
5240 * @count: number of items
5242 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5243 * This function must be used when @klass contains references fields.
5244 * Overlap is handled.
5247 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5249 int size = mono_array_element_size (dest->obj.vtable->klass);
5250 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5251 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5252 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5256 * mono_object_get_domain:
5257 * @obj: object to query
5259 * Returns: the MonoDomain where the object is hosted
5262 mono_object_get_domain (MonoObject *obj)
5264 return mono_object_domain (obj);
5268 * mono_object_get_class:
5269 * @obj: object to query
5271 * Returns: the MonOClass of the object.
5274 mono_object_get_class (MonoObject *obj)
5276 return mono_object_class (obj);
5279 * mono_object_get_size:
5280 * @o: object to query
5282 * Returns: the size, in bytes, of @o
5285 mono_object_get_size (MonoObject* o)
5287 MonoClass* klass = mono_object_class (o);
5288 if (klass == mono_defaults.string_class) {
5289 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5290 } else if (o->vtable->rank) {
5291 MonoArray *array = (MonoArray*)o;
5292 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5293 if (array->bounds) {
5296 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5300 return mono_class_instance_size (klass);
5305 * mono_object_unbox:
5306 * @obj: object to unbox
5308 * Returns: a pointer to the start of the valuetype boxed in this
5311 * This method will assert if the object passed is not a valuetype.
5314 mono_object_unbox (MonoObject *obj)
5316 /* add assert for valuetypes? */
5317 g_assert (obj->vtable->klass->valuetype);
5318 return ((char*)obj) + sizeof (MonoObject);
5322 * mono_object_isinst:
5324 * @klass: a pointer to a class
5326 * Returns: @obj if @obj is derived from @klass
5329 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5332 mono_class_init (klass);
5334 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5335 return mono_object_isinst_mbyref (obj, klass);
5340 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5344 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5353 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5354 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5358 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5359 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5362 MonoClass *oklass = vt->klass;
5363 if (mono_class_is_transparent_proxy (oklass))
5364 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5366 mono_class_setup_supertypes (klass);
5367 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5370 #ifndef DISABLE_REMOTING
5371 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5373 MonoDomain *domain = mono_domain_get ();
5375 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5376 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5377 MonoMethod *im = NULL;
5380 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5381 im = mono_object_get_virtual_method (rp, im);
5384 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5387 res = mono_runtime_invoke (im, rp, pa, NULL);
5389 if (*(MonoBoolean *) mono_object_unbox(res)) {
5390 /* Update the vtable of the remote type, so it can safely cast to this new type */
5391 mono_upgrade_remote_class (domain, obj, klass);
5395 #endif /* DISABLE_REMOTING */
5400 * mono_object_castclass_mbyref:
5402 * @klass: a pointer to a class
5404 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5407 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5409 if (!obj) return NULL;
5410 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5412 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5414 "InvalidCastException"));
5419 MonoDomain *orig_domain;
5425 str_lookup (MonoDomain *domain, gpointer user_data)
5427 LDStrInfo *info = user_data;
5428 if (info->res || domain == info->orig_domain)
5430 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5436 mono_string_get_pinned (MonoString *str)
5440 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5441 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5443 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5444 news->length = mono_string_length (str);
5450 #define mono_string_get_pinned(str) (str)
5454 mono_string_is_interned_lookup (MonoString *str, int insert)
5456 MonoGHashTable *ldstr_table;
5460 domain = ((MonoObject *)str)->vtable->domain;
5461 ldstr_table = domain->ldstr_table;
5463 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5468 str = mono_string_get_pinned (str);
5470 mono_g_hash_table_insert (ldstr_table, str, str);
5474 LDStrInfo ldstr_info;
5475 ldstr_info.orig_domain = domain;
5476 ldstr_info.ins = str;
5477 ldstr_info.res = NULL;
5479 mono_domain_foreach (str_lookup, &ldstr_info);
5480 if (ldstr_info.res) {
5482 * the string was already interned in some other domain:
5483 * intern it in the current one as well.
5485 mono_g_hash_table_insert (ldstr_table, str, str);
5495 * mono_string_is_interned:
5496 * @o: String to probe
5498 * Returns whether the string has been interned.
5501 mono_string_is_interned (MonoString *o)
5503 return mono_string_is_interned_lookup (o, FALSE);
5507 * mono_string_intern:
5508 * @o: String to intern
5510 * Interns the string passed.
5511 * Returns: The interned string.
5514 mono_string_intern (MonoString *str)
5516 return mono_string_is_interned_lookup (str, TRUE);
5521 * @domain: the domain where the string will be used.
5522 * @image: a metadata context
5523 * @idx: index into the user string table.
5525 * Implementation for the ldstr opcode.
5526 * Returns: a loaded string from the @image/@idx combination.
5529 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5531 MONO_ARCH_SAVE_REGS;
5533 if (image->dynamic) {
5534 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5537 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5538 return NULL; /*FIXME we should probably be raising an exception here*/
5539 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5544 * mono_ldstr_metadata_sig
5545 * @domain: the domain for the string
5546 * @sig: the signature of a metadata string
5548 * Returns: a MonoString for a string stored in the metadata
5551 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5553 const char *str = sig;
5554 MonoString *o, *interned;
5557 len2 = mono_metadata_decode_blob_size (str, &str);
5560 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5561 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5564 guint16 *p2 = (guint16*)mono_string_chars (o);
5565 for (i = 0; i < len2; ++i) {
5566 *p2 = GUINT16_FROM_LE (*p2);
5572 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5574 /* o will get garbage collected */
5578 o = mono_string_get_pinned (o);
5580 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5587 * mono_string_to_utf8:
5588 * @s: a System.String
5590 * Returns the UTF8 representation for @s.
5591 * The resulting buffer needs to be freed with mono_free().
5593 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5596 mono_string_to_utf8 (MonoString *s)
5599 char *result = mono_string_to_utf8_checked (s, &error);
5601 if (!mono_error_ok (&error))
5602 mono_error_raise_exception (&error);
5607 * mono_string_to_utf8_checked:
5608 * @s: a System.String
5609 * @error: a MonoError.
5611 * Converts a MonoString to its UTF8 representation. May fail; check
5612 * @error to determine whether the conversion was successful.
5613 * The resulting buffer should be freed with mono_free().
5616 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5620 GError *gerror = NULL;
5622 mono_error_init (error);
5628 return g_strdup ("");
5630 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5632 mono_error_set_argument (error, "string", "%s", gerror->message);
5633 g_error_free (gerror);
5636 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5637 if (s->length > written) {
5638 /* allocate the total length and copy the part of the string that has been converted */
5639 char *as2 = g_malloc0 (s->length);
5640 memcpy (as2, as, written);
5649 * mono_string_to_utf8_ignore:
5652 * Converts a MonoString to its UTF8 representation. Will ignore
5653 * invalid surrogate pairs.
5654 * The resulting buffer should be freed with mono_free().
5658 mono_string_to_utf8_ignore (MonoString *s)
5667 return g_strdup ("");
5669 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5671 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5672 if (s->length > written) {
5673 /* allocate the total length and copy the part of the string that has been converted */
5674 char *as2 = g_malloc0 (s->length);
5675 memcpy (as2, as, written);
5684 * mono_string_to_utf8_image_ignore:
5685 * @s: a System.String
5687 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5690 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5692 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5696 * mono_string_to_utf8_mp_ignore:
5697 * @s: a System.String
5699 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5702 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5704 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5709 * mono_string_to_utf16:
5712 * Return an null-terminated array of the utf-16 chars
5713 * contained in @s. The result must be freed with g_free().
5714 * This is a temporary helper until our string implementation
5715 * is reworked to always include the null terminating char.
5718 mono_string_to_utf16 (MonoString *s)
5725 as = g_malloc ((s->length * 2) + 2);
5726 as [(s->length * 2)] = '\0';
5727 as [(s->length * 2) + 1] = '\0';
5730 return (gunichar2 *)(as);
5733 memcpy (as, mono_string_chars(s), s->length * 2);
5734 return (gunichar2 *)(as);
5738 * mono_string_to_utf32:
5741 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5742 * contained in @s. The result must be freed with g_free().
5745 mono_string_to_utf32 (MonoString *s)
5747 mono_unichar4 *utf32_output = NULL;
5748 GError *error = NULL;
5749 glong items_written;
5754 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5757 g_error_free (error);
5759 return utf32_output;
5763 * mono_string_from_utf16:
5764 * @data: the UTF16 string (LPWSTR) to convert
5766 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5768 * Returns: a MonoString.
5771 mono_string_from_utf16 (gunichar2 *data)
5773 MonoDomain *domain = mono_domain_get ();
5779 while (data [len]) len++;
5781 return mono_string_new_utf16 (domain, data, len);
5785 * mono_string_from_utf32:
5786 * @data: the UTF32 string (LPWSTR) to convert
5788 * Converts a UTF32 (UCS-4)to a MonoString.
5790 * Returns: a MonoString.
5793 mono_string_from_utf32 (mono_unichar4 *data)
5795 MonoString* result = NULL;
5796 mono_unichar2 *utf16_output = NULL;
5797 GError *error = NULL;
5798 glong items_written;
5804 while (data [len]) len++;
5806 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5809 g_error_free (error);
5811 result = mono_string_from_utf16 (utf16_output);
5812 g_free (utf16_output);
5817 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5824 r = mono_string_to_utf8_ignore (s);
5826 r = mono_string_to_utf8_checked (s, error);
5827 if (!mono_error_ok (error))
5834 len = strlen (r) + 1;
5836 mp_s = mono_mempool_alloc (mp, len);
5838 mp_s = mono_image_alloc (image, len);
5840 memcpy (mp_s, r, len);
5848 * mono_string_to_utf8_image:
5849 * @s: a System.String
5851 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5854 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5856 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5860 * mono_string_to_utf8_mp:
5861 * @s: a System.String
5863 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5866 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5868 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5872 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5875 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5877 eh_callbacks = *cbs;
5880 MonoRuntimeExceptionHandlingCallbacks *
5881 mono_get_eh_callbacks (void)
5883 return &eh_callbacks;
5887 * mono_raise_exception:
5888 * @ex: exception object
5890 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5893 mono_raise_exception (MonoException *ex)
5896 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5897 * that will cause gcc to omit the function epilog, causing problems when
5898 * the JIT tries to walk the stack, since the return address on the stack
5899 * will point into the next function in the executable, not this one.
5901 eh_callbacks.mono_raise_exception (ex);
5905 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5907 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5911 * mono_wait_handle_new:
5912 * @domain: Domain where the object will be created
5913 * @handle: Handle for the wait handle
5915 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5918 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5920 MonoWaitHandle *res;
5921 gpointer params [1];
5922 static MonoMethod *handle_set;
5924 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5926 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5928 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5930 params [0] = &handle;
5931 mono_runtime_invoke (handle_set, res, params, NULL);
5937 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5939 static MonoClassField *f_os_handle;
5940 static MonoClassField *f_safe_handle;
5942 if (!f_os_handle && !f_safe_handle) {
5943 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5944 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5949 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5953 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5960 mono_runtime_capture_context (MonoDomain *domain)
5962 RuntimeInvokeFunction runtime_invoke;
5964 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5965 MonoMethod *method = mono_get_context_capture_method ();
5966 MonoMethod *wrapper;
5969 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5970 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5971 domain->capture_context_method = mono_compile_method (method);
5974 runtime_invoke = domain->capture_context_runtime_invoke;
5976 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5979 * mono_async_result_new:
5980 * @domain:domain where the object will be created.
5981 * @handle: wait handle.
5982 * @state: state to pass to AsyncResult
5983 * @data: C closure data.
5985 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5986 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5990 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5992 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5993 MonoObject *context = mono_runtime_capture_context (domain);
5994 /* we must capture the execution context from the original thread */
5996 MONO_OBJECT_SETREF (res, execution_context, context);
5997 /* note: result may be null if the flow is suppressed */
6001 MONO_OBJECT_SETREF (res, object_data, object_data);
6002 MONO_OBJECT_SETREF (res, async_state, state);
6004 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6006 res->sync_completed = FALSE;
6007 res->completed = FALSE;
6013 mono_message_init (MonoDomain *domain,
6014 MonoMethodMessage *this,
6015 MonoReflectionMethod *method,
6016 MonoArray *out_args)
6018 static MonoClass *object_array_klass;
6019 static MonoClass *byte_array_klass;
6020 static MonoClass *string_array_klass;
6021 MonoMethodSignature *sig = mono_method_signature (method->method);
6027 if (!object_array_klass) {
6030 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6032 byte_array_klass = klass;
6034 klass = mono_array_class_get (mono_defaults.string_class, 1);
6036 string_array_klass = klass;
6038 klass = mono_array_class_get (mono_defaults.object_class, 1);
6041 mono_atomic_store_release (&object_array_klass, klass);
6044 MONO_OBJECT_SETREF (this, method, method);
6046 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6047 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6048 this->async_result = NULL;
6049 this->call_type = CallType_Sync;
6051 names = g_new (char *, sig->param_count);
6052 mono_method_get_param_names (method->method, (const char **) names);
6053 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6055 for (i = 0; i < sig->param_count; i++) {
6056 name = mono_string_new (domain, names [i]);
6057 mono_array_setref (this->names, i, name);
6061 for (i = 0, j = 0; i < sig->param_count; i++) {
6062 if (sig->params [i]->byref) {
6064 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6065 mono_array_setref (this->args, i, arg);
6069 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6073 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6076 mono_array_set (this->arg_types, guint8, i, arg_type);
6080 #ifndef DISABLE_REMOTING
6082 * mono_remoting_invoke:
6083 * @real_proxy: pointer to a RealProxy object
6084 * @msg: The MonoMethodMessage to execute
6085 * @exc: used to store exceptions
6086 * @out_args: used to store output arguments
6088 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6089 * IMessage interface and it is not trivial to extract results from there. So
6090 * we call an helper method PrivateInvoke instead of calling
6091 * RealProxy::Invoke() directly.
6093 * Returns: the result object.
6096 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6097 MonoObject **exc, MonoArray **out_args)
6099 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6102 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6105 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6107 real_proxy->vtable->domain->private_invoke_method = im;
6110 pa [0] = real_proxy;
6115 return mono_runtime_invoke (im, NULL, pa, exc);
6120 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6121 MonoObject **exc, MonoArray **out_args)
6123 static MonoClass *object_array_klass;
6126 MonoMethodSignature *sig;
6128 int i, j, outarg_count = 0;
6130 #ifndef DISABLE_REMOTING
6131 if (target && mono_object_is_transparent_proxy (target)) {
6132 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6133 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6134 target = tp->rp->unwrapped_server;
6136 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6141 domain = mono_domain_get ();
6142 method = msg->method->method;
6143 sig = mono_method_signature (method);
6145 for (i = 0; i < sig->param_count; i++) {
6146 if (sig->params [i]->byref)
6150 if (!object_array_klass) {
6153 klass = mono_array_class_get (mono_defaults.object_class, 1);
6156 mono_memory_barrier ();
6157 object_array_klass = klass;
6160 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6161 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6164 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6166 for (i = 0, j = 0; i < sig->param_count; i++) {
6167 if (sig->params [i]->byref) {
6169 arg = mono_array_get (msg->args, gpointer, i);
6170 mono_array_setref (*out_args, j, arg);
6179 * mono_object_to_string:
6181 * @exc: Any exception thrown by ToString (). May be NULL.
6183 * Returns: the result of calling ToString () on an object.
6186 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6188 static MonoMethod *to_string = NULL;
6195 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6197 method = mono_object_get_virtual_method (obj, to_string);
6199 // Unbox value type if needed
6200 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6201 target = mono_object_unbox (obj);
6204 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6208 * mono_print_unhandled_exception:
6209 * @exc: The exception
6211 * Prints the unhandled exception.
6214 mono_print_unhandled_exception (MonoObject *exc)
6217 char *message = (char*)"";
6218 gboolean free_message = FALSE;
6221 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6222 message = g_strdup ("OutOfMemoryException");
6223 free_message = TRUE;
6226 if (((MonoException*)exc)->native_trace_ips) {
6227 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6228 free_message = TRUE;
6230 MonoObject *other_exc = NULL;
6231 str = mono_object_to_string (exc, &other_exc);
6233 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6234 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6236 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6237 original_backtrace, nested_backtrace);
6239 g_free (original_backtrace);
6240 g_free (nested_backtrace);
6241 free_message = TRUE;
6243 message = mono_string_to_utf8_checked (str, &error);
6244 if (!mono_error_ok (&error)) {
6245 mono_error_cleanup (&error);
6246 message = (char *) "";
6248 free_message = TRUE;
6255 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6256 * exc->vtable->klass->name, message);
6258 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6265 * mono_delegate_ctor:
6266 * @this: pointer to an uninitialized delegate object
6267 * @target: target object
6268 * @addr: pointer to native code
6271 * Initialize a delegate and sets a specific method, not the one
6272 * associated with addr. This is useful when sharing generic code.
6273 * In that case addr will most probably not be associated with the
6274 * correct instantiation of the method.
6277 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6279 MonoDelegate *delegate = (MonoDelegate *)this;
6286 delegate->method = method;
6288 class = this->vtable->klass;
6289 mono_stats.delegate_creations++;
6291 #ifndef DISABLE_REMOTING
6292 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6294 method = mono_marshal_get_remoting_invoke (method);
6295 delegate->method_ptr = mono_compile_method (method);
6296 MONO_OBJECT_SETREF (delegate, target, target);
6300 delegate->method_ptr = addr;
6301 MONO_OBJECT_SETREF (delegate, target, target);
6304 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6308 * mono_delegate_ctor:
6309 * @this: pointer to an uninitialized delegate object
6310 * @target: target object
6311 * @addr: pointer to native code
6313 * This is used to initialize a delegate.
6316 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6318 MonoDomain *domain = mono_domain_get ();
6320 MonoMethod *method = NULL;
6324 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6326 if (!ji && domain != mono_get_root_domain ())
6327 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6329 method = mono_jit_info_get_method (ji);
6330 g_assert (!method->klass->generic_container);
6333 mono_delegate_ctor_with_method (this, target, addr, method);
6337 * mono_method_call_message_new:
6338 * @method: method to encapsulate
6339 * @params: parameters to the method
6340 * @invoke: optional, delegate invoke.
6341 * @cb: async callback delegate.
6342 * @state: state passed to the async callback.
6344 * Translates arguments pointers into a MonoMethodMessage.
6347 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6348 MonoDelegate **cb, MonoObject **state)
6350 MonoDomain *domain = mono_domain_get ();
6351 MonoMethodSignature *sig = mono_method_signature (method);
6352 MonoMethodMessage *msg;
6355 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6358 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6359 count = sig->param_count - 2;
6361 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6362 count = sig->param_count;
6365 for (i = 0; i < count; i++) {
6370 if (sig->params [i]->byref)
6371 vpos = *((gpointer *)params [i]);
6375 type = sig->params [i]->type;
6376 class = mono_class_from_mono_type (sig->params [i]);
6378 if (class->valuetype)
6379 arg = mono_value_box (domain, class, vpos);
6381 arg = *((MonoObject **)vpos);
6383 mono_array_setref (msg->args, i, arg);
6386 if (cb != NULL && state != NULL) {
6387 *cb = *((MonoDelegate **)params [i]);
6389 *state = *((MonoObject **)params [i]);
6396 * mono_method_return_message_restore:
6398 * Restore results from message based processing back to arguments pointers
6401 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6403 MonoMethodSignature *sig = mono_method_signature (method);
6404 int i, j, type, size, out_len;
6406 if (out_args == NULL)
6408 out_len = mono_array_length (out_args);
6412 for (i = 0, j = 0; i < sig->param_count; i++) {
6413 MonoType *pt = sig->params [i];
6418 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6420 arg = mono_array_get (out_args, gpointer, j);
6423 g_assert (type != MONO_TYPE_VOID);
6425 if (MONO_TYPE_IS_REFERENCE (pt)) {
6426 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6429 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6430 size = mono_class_value_size (class, NULL);
6431 if (class->has_references)
6432 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6434 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6436 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6437 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6446 #ifndef DISABLE_REMOTING
6449 * mono_load_remote_field:
6450 * @this: pointer to an object
6451 * @klass: klass of the object containing @field
6452 * @field: the field to load
6453 * @res: a storage to store the result
6455 * This method is called by the runtime on attempts to load fields of
6456 * transparent proxy objects. @this points to such TP, @klass is the class of
6457 * the object containing @field. @res is a storage location which can be
6458 * used to store the result.
6460 * Returns: an address pointing to the value of field.
6463 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6465 static MonoMethod *getter = NULL;
6466 MonoDomain *domain = mono_domain_get ();
6467 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6468 MonoClass *field_class;
6469 MonoMethodMessage *msg;
6470 MonoArray *out_args;
6474 g_assert (mono_object_is_transparent_proxy (this));
6475 g_assert (res != NULL);
6477 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6478 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6483 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6487 field_class = mono_class_from_mono_type (field->type);
6489 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6490 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6491 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6493 full_name = mono_type_get_full_name (klass);
6494 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6495 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6498 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6500 if (exc) mono_raise_exception ((MonoException *)exc);
6502 if (mono_array_length (out_args) == 0)
6505 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6507 if (field_class->valuetype) {
6508 return ((char *)*res) + sizeof (MonoObject);
6514 * mono_load_remote_field_new:
6519 * Missing documentation.
6522 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6524 static MonoMethod *getter = NULL;
6525 MonoDomain *domain = mono_domain_get ();
6526 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6527 MonoClass *field_class;
6528 MonoMethodMessage *msg;
6529 MonoArray *out_args;
6530 MonoObject *exc, *res;
6533 g_assert (mono_object_is_transparent_proxy (this));
6535 field_class = mono_class_from_mono_type (field->type);
6537 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6539 if (field_class->valuetype) {
6540 res = mono_object_new (domain, field_class);
6541 val = ((gchar *) res) + sizeof (MonoObject);
6545 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6550 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6554 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6555 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6557 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6559 full_name = mono_type_get_full_name (klass);
6560 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6561 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6564 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6566 if (exc) mono_raise_exception ((MonoException *)exc);
6568 if (mono_array_length (out_args) == 0)
6571 res = mono_array_get (out_args, MonoObject *, 0);
6577 * mono_store_remote_field:
6578 * @this: pointer to an object
6579 * @klass: klass of the object containing @field
6580 * @field: the field to load
6581 * @val: the value/object to store
6583 * This method is called by the runtime on attempts to store fields of
6584 * transparent proxy objects. @this points to such TP, @klass is the class of
6585 * the object containing @field. @val is the new value to store in @field.
6588 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6590 static MonoMethod *setter = NULL;
6591 MonoDomain *domain = mono_domain_get ();
6592 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6593 MonoClass *field_class;
6594 MonoMethodMessage *msg;
6595 MonoArray *out_args;
6600 g_assert (mono_object_is_transparent_proxy (this));
6602 field_class = mono_class_from_mono_type (field->type);
6604 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6605 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6606 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6611 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6615 if (field_class->valuetype)
6616 arg = mono_value_box (domain, field_class, val);
6618 arg = *((MonoObject **)val);
6621 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6622 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6624 full_name = mono_type_get_full_name (klass);
6625 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6626 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6627 mono_array_setref (msg->args, 2, arg);
6630 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6632 if (exc) mono_raise_exception ((MonoException *)exc);
6636 * mono_store_remote_field_new:
6642 * Missing documentation
6645 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6647 static MonoMethod *setter = NULL;
6648 MonoDomain *domain = mono_domain_get ();
6649 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6650 MonoClass *field_class;
6651 MonoMethodMessage *msg;
6652 MonoArray *out_args;
6656 g_assert (mono_object_is_transparent_proxy (this));
6658 field_class = mono_class_from_mono_type (field->type);
6660 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6661 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6662 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6667 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6671 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6672 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6674 full_name = mono_type_get_full_name (klass);
6675 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6676 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6677 mono_array_setref (msg->args, 2, arg);
6680 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6682 if (exc) mono_raise_exception ((MonoException *)exc);
6687 * mono_create_ftnptr:
6689 * Given a function address, create a function descriptor for it.
6690 * This is only needed on some platforms.
6693 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6695 return callbacks.create_ftnptr (domain, addr);
6699 * mono_get_addr_from_ftnptr:
6701 * Given a pointer to a function descriptor, return the function address.
6702 * This is only needed on some platforms.
6705 mono_get_addr_from_ftnptr (gpointer descr)
6707 return callbacks.get_addr_from_ftnptr (descr);
6711 * mono_string_chars:
6714 * Returns a pointer to the UCS16 characters stored in the MonoString
6717 mono_string_chars (MonoString *s)
6723 * mono_string_length:
6726 * Returns the lenght in characters of the string
6729 mono_string_length (MonoString *s)
6735 * mono_array_length:
6736 * @array: a MonoArray*
6738 * Returns the total number of elements in the array. This works for
6739 * both vectors and multidimensional arrays.
6742 mono_array_length (MonoArray *array)
6744 return array->max_length;
6748 * mono_array_addr_with_size:
6749 * @array: a MonoArray*
6750 * @size: size of the array elements
6751 * @idx: index into the array
6753 * Returns the address of the @idx element in the array.
6756 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6758 return ((char*)(array)->vector) + size * idx;