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 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1857 size_t alloc_offset;
1860 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1861 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1862 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1864 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1865 g_assert ((imt_table_bytes & 7) == 4);
1872 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1876 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1879 MonoClassRuntimeInfo *runtime_info, *old_info;
1880 MonoClassField *field;
1882 int i, vtable_slots;
1883 size_t imt_table_bytes;
1885 guint32 vtable_size, class_size;
1888 gpointer *interface_offsets;
1890 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1891 mono_domain_lock (domain);
1892 runtime_info = class->runtime_info;
1893 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1894 mono_domain_unlock (domain);
1895 mono_loader_unlock ();
1896 return runtime_info->domain_vtables [domain->domain_id];
1898 if (!class->inited || class->exception_type) {
1899 if (!mono_class_init (class) || class->exception_type) {
1900 mono_domain_unlock (domain);
1901 mono_loader_unlock ();
1903 mono_raise_exception (mono_class_get_exception_for_failure (class));
1908 /* Array types require that their element type be valid*/
1909 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1910 MonoClass *element_class = class->element_class;
1911 if (!element_class->inited)
1912 mono_class_init (element_class);
1914 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1915 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1916 mono_class_setup_vtable (element_class);
1918 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1919 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1920 if (class->exception_type == MONO_EXCEPTION_NONE)
1921 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1922 mono_domain_unlock (domain);
1923 mono_loader_unlock ();
1925 mono_raise_exception (mono_class_get_exception_for_failure (class));
1931 * For some classes, mono_class_init () already computed class->vtable_size, and
1932 * that is all that is needed because of the vtable trampolines.
1934 if (!class->vtable_size)
1935 mono_class_setup_vtable (class);
1937 if (class->generic_class && !class->vtable)
1938 mono_class_check_vtable_constraints (class, NULL);
1940 /* Initialize klass->has_finalize */
1941 mono_class_has_finalizer (class);
1943 if (class->exception_type) {
1944 mono_domain_unlock (domain);
1945 mono_loader_unlock ();
1947 mono_raise_exception (mono_class_get_exception_for_failure (class));
1951 vtable_slots = class->vtable_size;
1952 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1953 class_size = mono_class_data_size (class);
1958 if (class->interface_offsets_count) {
1959 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1960 mono_stats.imt_number_of_tables++;
1961 mono_stats.imt_tables_size += imt_table_bytes;
1963 imt_table_bytes = 0;
1966 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1969 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1971 mono_stats.used_class_count++;
1972 mono_stats.class_vtable_size += vtable_size;
1974 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1975 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1976 g_assert (!((gsize)vt & 7));
1979 vt->rank = class->rank;
1980 vt->domain = domain;
1982 mono_class_compute_gc_descriptor (class);
1984 * We can't use typed allocation in the non-root domains, since the
1985 * collector needs the GC descriptor stored in the vtable even after
1986 * the mempool containing the vtable is destroyed when the domain is
1987 * unloaded. An alternative might be to allocate vtables in the GC
1988 * heap, but this does not seem to work (it leads to crashes inside
1989 * libgc). If that approach is tried, two gc descriptors need to be
1990 * allocated for each class: one for the root domain, and one for all
1991 * other domains. The second descriptor should contain a bit for the
1992 * vtable field in MonoObject, since we can no longer assume the
1993 * vtable is reachable by other roots after the appdomain is unloaded.
1995 #ifdef HAVE_BOEHM_GC
1996 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1997 vt->gc_descr = GC_NO_DESCRIPTOR;
2000 vt->gc_descr = class->gc_descr;
2002 gc_bits = mono_gc_get_vtable_bits (class);
2003 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2005 vt->gc_bits = gc_bits;
2008 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2009 if (class->has_static_refs) {
2010 gpointer statics_gc_descr;
2012 gsize default_bitmap [4] = {0};
2015 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2016 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2017 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2018 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2019 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2020 if (bitmap != default_bitmap)
2023 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2025 vt->has_static_fields = TRUE;
2026 mono_stats.class_static_data_size += class_size;
2031 while ((field = mono_class_get_fields (class, &iter))) {
2032 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2034 if (mono_field_is_deleted (field))
2036 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2037 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2038 if (special_static != SPECIAL_STATIC_NONE) {
2039 guint32 size, offset;
2041 gsize default_bitmap [4] = {0};
2046 if (mono_type_is_reference (field->type)) {
2047 default_bitmap [0] = 1;
2049 bitmap = default_bitmap;
2050 } else if (mono_type_is_struct (field->type)) {
2051 fclass = mono_class_from_mono_type (field->type);
2052 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2053 numbits = max_set + 1;
2055 default_bitmap [0] = 0;
2057 bitmap = default_bitmap;
2059 size = mono_type_size (field->type, &align);
2060 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2061 if (!domain->special_static_fields)
2062 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2063 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2064 if (bitmap != default_bitmap)
2067 * This marks the field as special static to speed up the
2068 * checks in mono_field_static_get/set_value ().
2074 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2075 MonoClass *fklass = mono_class_from_mono_type (field->type);
2076 const char *data = mono_field_get_data (field);
2078 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2079 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2080 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2083 if (fklass->valuetype) {
2084 memcpy (t, data, mono_class_value_size (fklass, NULL));
2086 /* it's a pointer type: add check */
2087 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2094 vt->max_interface_id = class->max_interface_id;
2095 vt->interface_bitmap = class->interface_bitmap;
2097 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2098 // class->name, class->interface_offsets_count);
2100 if (! ARCH_USE_IMT) {
2101 /* initialize interface offsets */
2102 for (i = 0; i < class->interface_offsets_count; ++i) {
2103 int interface_id = class->interfaces_packed [i]->interface_id;
2104 int slot = class->interface_offsets_packed [i];
2105 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2109 /* Initialize vtable */
2110 if (callbacks.get_vtable_trampoline) {
2111 // This also covers the AOT case
2112 for (i = 0; i < class->vtable_size; ++i) {
2113 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2116 mono_class_setup_vtable (class);
2118 for (i = 0; i < class->vtable_size; ++i) {
2121 if ((cm = class->vtable [i]))
2122 vt->vtable [i] = arch_create_jit_trampoline (cm);
2126 if (ARCH_USE_IMT && imt_table_bytes) {
2127 /* Now that the vtable is full, we can actually fill up the IMT */
2128 if (callbacks.get_imt_trampoline) {
2129 /* lazy construction of the IMT entries enabled */
2130 for (i = 0; i < MONO_IMT_SIZE; ++i)
2131 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2133 build_imt (class, vt, domain, interface_offsets, NULL);
2138 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2139 * re-acquire them and check if another thread has created the vtable in the meantime.
2141 /* Special case System.MonoType to avoid infinite recursion */
2142 if (class != mono_defaults.monotype_class) {
2143 /*FIXME check for OOM*/
2144 vt->type = mono_type_get_object (domain, &class->byval_arg);
2145 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2146 /* This is unregistered in
2147 unregister_vtable_reflection_type() in
2149 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2152 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2154 /* class_vtable_array keeps an array of created vtables
2156 g_ptr_array_add (domain->class_vtable_array, vt);
2157 /* class->runtime_info is protected by the loader lock, both when
2158 * it it enlarged and when it is stored info.
2162 * Store the vtable in class->runtime_info.
2163 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2165 mono_memory_barrier ();
2167 old_info = class->runtime_info;
2168 if (old_info && old_info->max_domain >= domain->domain_id) {
2169 /* someone already created a large enough runtime info */
2170 old_info->domain_vtables [domain->domain_id] = vt;
2172 int new_size = domain->domain_id;
2174 new_size = MAX (new_size, old_info->max_domain);
2176 /* make the new size a power of two */
2178 while (new_size > i)
2181 /* this is a bounded memory retention issue: may want to
2182 * handle it differently when we'll have a rcu-like system.
2184 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2185 runtime_info->max_domain = new_size - 1;
2186 /* copy the stuff from the older info */
2188 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2190 runtime_info->domain_vtables [domain->domain_id] = vt;
2192 mono_memory_barrier ();
2193 class->runtime_info = runtime_info;
2196 if (class == mono_defaults.monotype_class) {
2197 /*FIXME check for OOM*/
2198 vt->type = mono_type_get_object (domain, &class->byval_arg);
2199 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2200 /* This is unregistered in
2201 unregister_vtable_reflection_type() in
2203 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2206 mono_domain_unlock (domain);
2207 mono_loader_unlock ();
2209 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2210 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2211 mono_raise_exception (mono_class_get_exception_for_failure (class));
2213 /* make sure the parent is initialized */
2214 /*FIXME shouldn't this fail the current type?*/
2216 mono_class_vtable_full (domain, class->parent, raise_on_error);
2221 #ifndef DISABLE_REMOTING
2223 * mono_class_proxy_vtable:
2224 * @domain: the application domain
2225 * @remove_class: the remote class
2227 * Creates a vtable for transparent proxies. It is basically
2228 * a copy of the real vtable of the class wrapped in @remote_class,
2229 * but all function pointers invoke the remoting functions, and
2230 * vtable->klass points to the transparent proxy class, and not to @class.
2233 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2236 MonoVTable *vt, *pvt;
2237 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2239 GSList *extra_interfaces = NULL;
2240 MonoClass *class = remote_class->proxy_class;
2241 gpointer *interface_offsets;
2244 size_t imt_table_bytes;
2246 #ifdef COMPRESSED_INTERFACE_BITMAP
2250 vt = mono_class_vtable (domain, class);
2251 g_assert (vt); /*FIXME property handle failure*/
2252 max_interface_id = vt->max_interface_id;
2254 /* Calculate vtable space for extra interfaces */
2255 for (j = 0; j < remote_class->interface_count; j++) {
2256 MonoClass* iclass = remote_class->interfaces[j];
2260 /*FIXME test for interfaces with variant generic arguments*/
2261 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2262 continue; /* interface implemented by the class */
2263 if (g_slist_find (extra_interfaces, iclass))
2266 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2268 method_count = mono_class_num_methods (iclass);
2270 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2271 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2273 for (i = 0; i < ifaces->len; ++i) {
2274 MonoClass *ic = g_ptr_array_index (ifaces, i);
2275 /*FIXME test for interfaces with variant generic arguments*/
2276 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2277 continue; /* interface implemented by the class */
2278 if (g_slist_find (extra_interfaces, ic))
2280 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2281 method_count += mono_class_num_methods (ic);
2283 g_ptr_array_free (ifaces, TRUE);
2286 extra_interface_vtsize += method_count * sizeof (gpointer);
2287 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2291 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2292 mono_stats.imt_number_of_tables++;
2293 mono_stats.imt_tables_size += imt_table_bytes;
2295 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2298 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2300 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2302 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2303 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2304 g_assert (!((gsize)pvt & 7));
2306 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2308 pvt->klass = mono_defaults.transparent_proxy_class;
2309 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2310 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2312 /* initialize vtable */
2313 mono_class_setup_vtable (class);
2314 for (i = 0; i < class->vtable_size; ++i) {
2317 if ((cm = class->vtable [i]))
2318 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2320 pvt->vtable [i] = NULL;
2323 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2324 /* create trampolines for abstract methods */
2325 for (k = class; k; k = k->parent) {
2327 gpointer iter = NULL;
2328 while ((m = mono_class_get_methods (k, &iter)))
2329 if (!pvt->vtable [m->slot])
2330 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2334 pvt->max_interface_id = max_interface_id;
2335 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2336 #ifdef COMPRESSED_INTERFACE_BITMAP
2337 bitmap = g_malloc0 (bsize);
2339 bitmap = mono_domain_alloc0 (domain, bsize);
2342 if (! ARCH_USE_IMT) {
2343 /* initialize interface offsets */
2344 for (i = 0; i < class->interface_offsets_count; ++i) {
2345 int interface_id = class->interfaces_packed [i]->interface_id;
2346 int slot = class->interface_offsets_packed [i];
2347 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2350 for (i = 0; i < class->interface_offsets_count; ++i) {
2351 int interface_id = class->interfaces_packed [i]->interface_id;
2352 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2355 if (extra_interfaces) {
2356 int slot = class->vtable_size;
2362 /* Create trampolines for the methods of the interfaces */
2363 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2364 interf = list_item->data;
2366 if (! ARCH_USE_IMT) {
2367 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2369 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2373 while ((cm = mono_class_get_methods (interf, &iter)))
2374 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2376 slot += mono_class_num_methods (interf);
2378 if (! ARCH_USE_IMT) {
2379 g_slist_free (extra_interfaces);
2384 /* Now that the vtable is full, we can actually fill up the IMT */
2385 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2386 if (extra_interfaces) {
2387 g_slist_free (extra_interfaces);
2391 #ifdef COMPRESSED_INTERFACE_BITMAP
2392 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2393 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2394 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2397 pvt->interface_bitmap = bitmap;
2402 #endif /* DISABLE_REMOTING */
2405 * mono_class_field_is_special_static:
2407 * Returns whether @field is a thread/context static field.
2410 mono_class_field_is_special_static (MonoClassField *field)
2412 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2414 if (mono_field_is_deleted (field))
2416 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2417 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2424 * mono_class_field_get_special_static_type:
2425 * @field: The MonoClassField describing the field.
2427 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2428 * SPECIAL_STATIC_NONE otherwise.
2431 mono_class_field_get_special_static_type (MonoClassField *field)
2433 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2434 return SPECIAL_STATIC_NONE;
2435 if (mono_field_is_deleted (field))
2436 return SPECIAL_STATIC_NONE;
2437 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2438 return field_is_special_static (field->parent, field);
2439 return SPECIAL_STATIC_NONE;
2443 * mono_class_has_special_static_fields:
2445 * Returns whenever @klass has any thread/context static fields.
2448 mono_class_has_special_static_fields (MonoClass *klass)
2450 MonoClassField *field;
2454 while ((field = mono_class_get_fields (klass, &iter))) {
2455 g_assert (field->parent == klass);
2456 if (mono_class_field_is_special_static (field))
2463 #ifndef DISABLE_REMOTING
2465 * create_remote_class_key:
2466 * Creates an array of pointers that can be used as a hash key for a remote class.
2467 * The first element of the array is the number of pointers.
2470 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2475 if (remote_class == NULL) {
2476 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2477 key = g_malloc (sizeof(gpointer) * 3);
2478 key [0] = GINT_TO_POINTER (2);
2479 key [1] = mono_defaults.marshalbyrefobject_class;
2480 key [2] = extra_class;
2482 key = g_malloc (sizeof(gpointer) * 2);
2483 key [0] = GINT_TO_POINTER (1);
2484 key [1] = extra_class;
2487 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2488 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2489 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2490 key [1] = remote_class->proxy_class;
2492 // Keep the list of interfaces sorted
2493 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2494 if (extra_class && remote_class->interfaces [i] > extra_class) {
2495 key [j++] = extra_class;
2498 key [j] = remote_class->interfaces [i];
2501 key [j] = extra_class;
2503 // Replace the old class. The interface list is the same
2504 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2505 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2506 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2507 for (i = 0; i < remote_class->interface_count; i++)
2508 key [2 + i] = remote_class->interfaces [i];
2516 * copy_remote_class_key:
2518 * Make a copy of KEY in the domain and return the copy.
2521 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2523 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2524 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2526 memcpy (mp_key, key, key_size);
2532 * mono_remote_class:
2533 * @domain: the application domain
2534 * @class_name: name of the remote class
2536 * Creates and initializes a MonoRemoteClass object for a remote type.
2538 * Can raise an exception on failure.
2541 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2544 MonoRemoteClass *rc;
2545 gpointer* key, *mp_key;
2548 key = create_remote_class_key (NULL, proxy_class);
2550 mono_domain_lock (domain);
2551 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2555 mono_domain_unlock (domain);
2559 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2560 if (!mono_error_ok (&error)) {
2562 mono_domain_unlock (domain);
2563 mono_error_raise_exception (&error);
2566 mp_key = copy_remote_class_key (domain, key);
2570 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2571 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2572 rc->interface_count = 1;
2573 rc->interfaces [0] = proxy_class;
2574 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2576 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2577 rc->interface_count = 0;
2578 rc->proxy_class = proxy_class;
2581 rc->default_vtable = NULL;
2582 rc->xdomain_vtable = NULL;
2583 rc->proxy_class_name = name;
2584 #ifndef DISABLE_PERFCOUNTERS
2585 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2588 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2590 mono_domain_unlock (domain);
2595 * clone_remote_class:
2596 * Creates a copy of the remote_class, adding the provided class or interface
2598 static MonoRemoteClass*
2599 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2601 MonoRemoteClass *rc;
2602 gpointer* key, *mp_key;
2604 key = create_remote_class_key (remote_class, extra_class);
2605 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2611 mp_key = copy_remote_class_key (domain, key);
2615 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2617 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2618 rc->proxy_class = remote_class->proxy_class;
2619 rc->interface_count = remote_class->interface_count + 1;
2621 // Keep the list of interfaces sorted, since the hash key of
2622 // the remote class depends on this
2623 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2624 if (remote_class->interfaces [i] > extra_class && i == j)
2625 rc->interfaces [j++] = extra_class;
2626 rc->interfaces [j] = remote_class->interfaces [i];
2629 rc->interfaces [j] = extra_class;
2631 // Replace the old class. The interface array is the same
2632 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2633 rc->proxy_class = extra_class;
2634 rc->interface_count = remote_class->interface_count;
2635 if (rc->interface_count > 0)
2636 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2639 rc->default_vtable = NULL;
2640 rc->xdomain_vtable = NULL;
2641 rc->proxy_class_name = remote_class->proxy_class_name;
2643 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2649 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2651 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2652 mono_domain_lock (domain);
2653 if (rp->target_domain_id != -1) {
2654 if (remote_class->xdomain_vtable == NULL)
2655 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2656 mono_domain_unlock (domain);
2657 mono_loader_unlock ();
2658 return remote_class->xdomain_vtable;
2660 if (remote_class->default_vtable == NULL) {
2663 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2664 klass = mono_class_from_mono_type (type);
2666 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)))
2667 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2670 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2673 mono_domain_unlock (domain);
2674 mono_loader_unlock ();
2675 return remote_class->default_vtable;
2679 * mono_upgrade_remote_class:
2680 * @domain: the application domain
2681 * @tproxy: the proxy whose remote class has to be upgraded.
2682 * @klass: class to which the remote class can be casted.
2684 * Updates the vtable of the remote class by adding the necessary method slots
2685 * and interface offsets so it can be safely casted to klass. klass can be a
2686 * class or an interface.
2689 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2691 MonoTransparentProxy *tproxy;
2692 MonoRemoteClass *remote_class;
2693 gboolean redo_vtable;
2695 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2696 mono_domain_lock (domain);
2698 tproxy = (MonoTransparentProxy*) proxy_object;
2699 remote_class = tproxy->remote_class;
2701 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2704 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2705 if (remote_class->interfaces [i] == klass)
2706 redo_vtable = FALSE;
2709 redo_vtable = (remote_class->proxy_class != klass);
2713 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2714 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2717 mono_domain_unlock (domain);
2718 mono_loader_unlock ();
2720 #endif /* DISABLE_REMOTING */
2724 * mono_object_get_virtual_method:
2725 * @obj: object to operate on.
2728 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2729 * the instance of a callvirt of method.
2732 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2735 MonoMethod **vtable;
2736 gboolean is_proxy = FALSE;
2737 MonoMethod *res = NULL;
2739 klass = mono_object_class (obj);
2740 #ifndef DISABLE_REMOTING
2741 if (klass == mono_defaults.transparent_proxy_class) {
2742 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2747 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2750 mono_class_setup_vtable (klass);
2751 vtable = klass->vtable;
2753 if (method->slot == -1) {
2754 /* method->slot might not be set for instances of generic methods */
2755 if (method->is_inflated) {
2756 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2757 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2760 g_assert_not_reached ();
2764 /* check method->slot is a valid index: perform isinstance? */
2765 if (method->slot != -1) {
2766 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2768 gboolean variance_used = FALSE;
2769 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2770 g_assert (iface_offset > 0);
2771 res = vtable [iface_offset + method->slot];
2774 res = vtable [method->slot];
2778 #ifndef DISABLE_REMOTING
2780 /* It may be an interface, abstract class method or generic method */
2781 if (!res || mono_method_signature (res)->generic_param_count)
2784 /* generic methods demand invoke_with_check */
2785 if (mono_method_signature (res)->generic_param_count)
2786 res = mono_marshal_get_remoting_invoke_with_check (res);
2789 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2790 res = mono_cominterop_get_invoke (res);
2793 res = mono_marshal_get_remoting_invoke (res);
2798 if (method->is_inflated) {
2799 /* Have to inflate the result */
2800 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2810 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2812 g_error ("runtime invoke called on uninitialized runtime");
2816 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2819 * mono_runtime_invoke:
2820 * @method: method to invoke
2821 * @obJ: object instance
2822 * @params: arguments to the method
2823 * @exc: exception information.
2825 * Invokes the method represented by @method on the object @obj.
2827 * obj is the 'this' pointer, it should be NULL for static
2828 * methods, a MonoObject* for object instances and a pointer to
2829 * the value type for value types.
2831 * The params array contains the arguments to the method with the
2832 * same convention: MonoObject* pointers for object instances and
2833 * pointers to the value type otherwise.
2835 * From unmanaged code you'll usually use the
2836 * mono_runtime_invoke() variant.
2838 * Note that this function doesn't handle virtual methods for
2839 * you, it will exec the exact method you pass: we still need to
2840 * expose a function to lookup the derived class implementation
2841 * of a virtual method (there are examples of this in the code,
2844 * You can pass NULL as the exc argument if you don't want to
2845 * catch exceptions, otherwise, *exc will be set to the exception
2846 * thrown, if any. if an exception is thrown, you can't use the
2847 * MonoObject* result from the function.
2849 * If the method returns a value type, it is boxed in an object
2853 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2857 if (mono_runtime_get_no_exec ())
2858 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2860 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2861 mono_profiler_method_start_invoke (method);
2863 result = default_mono_runtime_invoke (method, obj, params, exc);
2865 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2866 mono_profiler_method_end_invoke (method);
2872 * mono_method_get_unmanaged_thunk:
2873 * @method: method to generate a thunk for.
2875 * Returns an unmanaged->managed thunk that can be used to call
2876 * a managed method directly from C.
2878 * The thunk's C signature closely matches the managed signature:
2880 * C#: public bool Equals (object obj);
2881 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2882 * MonoObject*, MonoException**);
2884 * The 1st ("this") parameter must not be used with static methods:
2886 * C#: public static bool ReferenceEquals (object a, object b);
2887 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2890 * The last argument must be a non-null pointer of a MonoException* pointer.
2891 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2892 * exception has been thrown in managed code. Otherwise it will point
2893 * to the MonoException* caught by the thunk. In this case, the result of
2894 * the thunk is undefined:
2896 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2897 * MonoException *ex = NULL;
2898 * Equals func = mono_method_get_unmanaged_thunk (method);
2899 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2901 * // handle exception
2904 * The calling convention of the thunk matches the platform's default
2905 * convention. This means that under Windows, C declarations must
2906 * contain the __stdcall attribute:
2908 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2909 * MonoObject*, MonoException**);
2913 * Value type arguments and return values are treated as they were objects:
2915 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2916 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2918 * Arguments must be properly boxed upon trunk's invocation, while return
2919 * values must be unboxed.
2922 mono_method_get_unmanaged_thunk (MonoMethod *method)
2924 method = mono_marshal_get_thunk_invoke_wrapper (method);
2925 return mono_compile_method (method);
2929 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2933 /* object fields cannot be byref, so we don't need a
2935 gpointer *p = (gpointer*)dest;
2942 case MONO_TYPE_BOOLEAN:
2944 case MONO_TYPE_U1: {
2945 guint8 *p = (guint8*)dest;
2946 *p = value ? *(guint8*)value : 0;
2951 case MONO_TYPE_CHAR: {
2952 guint16 *p = (guint16*)dest;
2953 *p = value ? *(guint16*)value : 0;
2956 #if SIZEOF_VOID_P == 4
2961 case MONO_TYPE_U4: {
2962 gint32 *p = (gint32*)dest;
2963 *p = value ? *(gint32*)value : 0;
2966 #if SIZEOF_VOID_P == 8
2971 case MONO_TYPE_U8: {
2972 gint64 *p = (gint64*)dest;
2973 *p = value ? *(gint64*)value : 0;
2976 case MONO_TYPE_R4: {
2977 float *p = (float*)dest;
2978 *p = value ? *(float*)value : 0;
2981 case MONO_TYPE_R8: {
2982 double *p = (double*)dest;
2983 *p = value ? *(double*)value : 0;
2986 case MONO_TYPE_STRING:
2987 case MONO_TYPE_SZARRAY:
2988 case MONO_TYPE_CLASS:
2989 case MONO_TYPE_OBJECT:
2990 case MONO_TYPE_ARRAY:
2991 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2993 case MONO_TYPE_FNPTR:
2994 case MONO_TYPE_PTR: {
2995 gpointer *p = (gpointer*)dest;
2996 *p = deref_pointer? *(gpointer*)value: value;
2999 case MONO_TYPE_VALUETYPE:
3000 /* note that 't' and 'type->type' can be different */
3001 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3002 t = mono_class_enum_basetype (type->data.klass)->type;
3005 MonoClass *class = mono_class_from_mono_type (type);
3006 int size = mono_class_value_size (class, NULL);
3008 mono_gc_bzero_atomic (dest, size);
3010 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3013 case MONO_TYPE_GENERICINST:
3014 t = type->data.generic_class->container_class->byval_arg.type;
3017 g_error ("got type %x", type->type);
3022 * mono_field_set_value:
3023 * @obj: Instance object
3024 * @field: MonoClassField describing the field to set
3025 * @value: The value to be set
3027 * Sets the value of the field described by @field in the object instance @obj
3028 * to the value passed in @value. This method should only be used for instance
3029 * fields. For static fields, use mono_field_static_set_value.
3031 * The value must be on the native format of the field type.
3034 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3038 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3040 dest = (char*)obj + field->offset;
3041 set_value (field->type, dest, value, FALSE);
3045 * mono_field_static_set_value:
3046 * @field: MonoClassField describing the field to set
3047 * @value: The value to be set
3049 * Sets the value of the static field described by @field
3050 * to the value passed in @value.
3052 * The value must be on the native format of the field type.
3055 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3059 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3060 /* you cant set a constant! */
3061 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3063 if (field->offset == -1) {
3064 /* Special static */
3067 mono_domain_lock (vt->domain);
3068 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3069 mono_domain_unlock (vt->domain);
3070 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3072 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3074 set_value (field->type, dest, value, FALSE);
3078 * mono_vtable_get_static_field_data:
3080 * Internal use function: return a pointer to the memory holding the static fields
3081 * for a class or NULL if there are no static fields.
3082 * This is exported only for use by the debugger.
3085 mono_vtable_get_static_field_data (MonoVTable *vt)
3087 if (!vt->has_static_fields)
3089 return vt->vtable [vt->klass->vtable_size];
3093 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3097 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3098 if (field->offset == -1) {
3099 /* Special static */
3102 mono_domain_lock (vt->domain);
3103 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3104 mono_domain_unlock (vt->domain);
3105 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3107 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3110 src = (guint8*)obj + field->offset;
3117 * mono_field_get_value:
3118 * @obj: Object instance
3119 * @field: MonoClassField describing the field to fetch information from
3120 * @value: pointer to the location where the value will be stored
3122 * Use this routine to get the value of the field @field in the object
3125 * The pointer provided by value must be of the field type, for reference
3126 * types this is a MonoObject*, for value types its the actual pointer to
3131 * mono_field_get_value (obj, int_field, &i);
3134 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3140 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3142 src = (char*)obj + field->offset;
3143 set_value (field->type, value, src, TRUE);
3147 * mono_field_get_value_object:
3148 * @domain: domain where the object will be created (if boxing)
3149 * @field: MonoClassField describing the field to fetch information from
3150 * @obj: The object instance for the field.
3152 * Returns: a new MonoObject with the value from the given field. If the
3153 * field represents a value type, the value is boxed.
3157 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3161 MonoVTable *vtable = NULL;
3163 gboolean is_static = FALSE;
3164 gboolean is_ref = FALSE;
3165 gboolean is_literal = FALSE;
3166 gboolean is_ptr = FALSE;
3168 MonoType *type = mono_field_get_type_checked (field, &error);
3170 if (!mono_error_ok (&error))
3171 mono_error_raise_exception (&error);
3173 switch (type->type) {
3174 case MONO_TYPE_STRING:
3175 case MONO_TYPE_OBJECT:
3176 case MONO_TYPE_CLASS:
3177 case MONO_TYPE_ARRAY:
3178 case MONO_TYPE_SZARRAY:
3183 case MONO_TYPE_BOOLEAN:
3186 case MONO_TYPE_CHAR:
3195 case MONO_TYPE_VALUETYPE:
3196 is_ref = type->byref;
3198 case MONO_TYPE_GENERICINST:
3199 is_ref = !mono_type_generic_inst_is_valuetype (type);
3205 g_error ("type 0x%x not handled in "
3206 "mono_field_get_value_object", type->type);
3210 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3213 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3217 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3218 if (!vtable->initialized)
3219 mono_runtime_class_init (vtable);
3227 get_default_field_value (domain, field, &o);
3228 } else if (is_static) {
3229 mono_field_static_get_value (vtable, field, &o);
3231 mono_field_get_value (obj, field, &o);
3237 static MonoMethod *m;
3243 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3244 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3250 get_default_field_value (domain, field, v);
3251 } else if (is_static) {
3252 mono_field_static_get_value (vtable, field, v);
3254 mono_field_get_value (obj, field, v);
3257 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3259 args [1] = mono_type_get_object (mono_domain_get (), type);
3261 return mono_runtime_invoke (m, NULL, args, NULL);
3264 /* boxed value type */
3265 klass = mono_class_from_mono_type (type);
3267 if (mono_class_is_nullable (klass))
3268 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3270 o = mono_object_new (domain, klass);
3271 v = ((gchar *) o) + sizeof (MonoObject);
3274 get_default_field_value (domain, field, v);
3275 } else if (is_static) {
3276 mono_field_static_get_value (vtable, field, v);
3278 mono_field_get_value (obj, field, v);
3285 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3288 const char *p = blob;
3289 mono_metadata_decode_blob_size (p, &p);
3292 case MONO_TYPE_BOOLEAN:
3295 *(guint8 *) value = *p;
3297 case MONO_TYPE_CHAR:
3300 *(guint16*) value = read16 (p);
3304 *(guint32*) value = read32 (p);
3308 *(guint64*) value = read64 (p);
3311 readr4 (p, (float*) value);
3314 readr8 (p, (double*) value);
3316 case MONO_TYPE_STRING:
3317 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3319 case MONO_TYPE_CLASS:
3320 *(gpointer*) value = NULL;
3324 g_warning ("type 0x%02x should not be in constant table", type);
3330 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3332 MonoTypeEnum def_type;
3335 data = mono_class_get_field_default_value (field, &def_type);
3336 mono_get_constant_value_from_blob (domain, def_type, data, value);
3340 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3344 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3346 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3347 get_default_field_value (vt->domain, field, value);
3351 if (field->offset == -1) {
3352 /* Special static */
3353 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3354 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3356 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3358 set_value (field->type, value, src, TRUE);
3362 * mono_field_static_get_value:
3363 * @vt: vtable to the object
3364 * @field: MonoClassField describing the field to fetch information from
3365 * @value: where the value is returned
3367 * Use this routine to get the value of the static field @field value.
3369 * The pointer provided by value must be of the field type, for reference
3370 * types this is a MonoObject*, for value types its the actual pointer to
3375 * mono_field_static_get_value (vt, int_field, &i);
3378 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3380 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3384 * mono_property_set_value:
3385 * @prop: MonoProperty to set
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 set 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.
3399 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3401 default_mono_runtime_invoke (prop->set, obj, params, exc);
3405 * mono_property_get_value:
3406 * @prop: MonoProperty to fetch
3407 * @obj: instance object on which to act
3408 * @params: parameters to pass to the propery
3409 * @exc: optional exception
3411 * Invokes the property's get method with the given arguments on the
3412 * object instance obj (or NULL for static properties).
3414 * You can pass NULL as the exc argument if you don't want to
3415 * catch exceptions, otherwise, *exc will be set to the exception
3416 * thrown, if any. if an exception is thrown, you can't use the
3417 * MonoObject* result from the function.
3419 * Returns: the value from invoking the get method on the property.
3422 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3424 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3428 * mono_nullable_init:
3429 * @buf: The nullable structure to initialize.
3430 * @value: the value to initialize from
3431 * @klass: the type for the object
3433 * Initialize the nullable structure pointed to by @buf from @value which
3434 * should be a boxed value type. The size of @buf should be able to hold
3435 * as much data as the @klass->instance_size (which is the number of bytes
3436 * that will be copies).
3438 * Since Nullables have variable structure, we can not define a C
3439 * structure for them.
3442 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3444 MonoClass *param_class = klass->cast_class;
3446 mono_class_setup_fields_locking (klass);
3447 g_assert (klass->fields_inited);
3449 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3450 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3452 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3454 if (param_class->has_references)
3455 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3457 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3459 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3464 * mono_nullable_box:
3465 * @buf: The buffer representing the data to be boxed
3466 * @klass: the type to box it as.
3468 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3472 mono_nullable_box (guint8 *buf, MonoClass *klass)
3474 MonoClass *param_class = klass->cast_class;
3476 mono_class_setup_fields_locking (klass);
3477 g_assert (klass->fields_inited);
3479 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3480 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3482 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3483 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3484 if (param_class->has_references)
3485 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3487 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3495 * mono_get_delegate_invoke:
3496 * @klass: The delegate class
3498 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3501 mono_get_delegate_invoke (MonoClass *klass)
3505 /* This is called at runtime, so avoid the slower search in metadata */
3506 mono_class_setup_methods (klass);
3507 if (klass->exception_type)
3509 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3514 * mono_get_delegate_begin_invoke:
3515 * @klass: The delegate class
3517 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3520 mono_get_delegate_begin_invoke (MonoClass *klass)
3524 /* This is called at runtime, so avoid the slower search in metadata */
3525 mono_class_setup_methods (klass);
3526 if (klass->exception_type)
3528 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3533 * mono_get_delegate_end_invoke:
3534 * @klass: The delegate class
3536 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3539 mono_get_delegate_end_invoke (MonoClass *klass)
3543 /* This is called at runtime, so avoid the slower search in metadata */
3544 mono_class_setup_methods (klass);
3545 if (klass->exception_type)
3547 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3552 * mono_runtime_delegate_invoke:
3553 * @delegate: pointer to a delegate object.
3554 * @params: parameters for the delegate.
3555 * @exc: Pointer to the exception result.
3557 * Invokes the delegate method @delegate with the parameters provided.
3559 * You can pass NULL as the exc argument if you don't want to
3560 * catch exceptions, otherwise, *exc will be set to the exception
3561 * thrown, if any. if an exception is thrown, you can't use the
3562 * MonoObject* result from the function.
3565 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3568 MonoClass *klass = delegate->vtable->klass;
3570 im = mono_get_delegate_invoke (klass);
3572 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3574 return mono_runtime_invoke (im, delegate, params, exc);
3577 static char **main_args = NULL;
3578 static int num_main_args = 0;
3581 * mono_runtime_get_main_args:
3583 * Returns: a MonoArray with the arguments passed to the main program
3586 mono_runtime_get_main_args (void)
3590 MonoDomain *domain = mono_domain_get ();
3592 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3594 for (i = 0; i < num_main_args; ++i)
3595 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3601 free_main_args (void)
3605 for (i = 0; i < num_main_args; ++i)
3606 g_free (main_args [i]);
3613 * mono_runtime_set_main_args:
3614 * @argc: number of arguments from the command line
3615 * @argv: array of strings from the command line
3617 * Set the command line arguments from an embedding application that doesn't otherwise call
3618 * mono_runtime_run_main ().
3621 mono_runtime_set_main_args (int argc, char* argv[])
3626 main_args = g_new0 (char*, argc);
3627 num_main_args = argc;
3629 for (i = 0; i < argc; ++i) {
3632 utf8_arg = mono_utf8_from_external (argv[i]);
3633 if (utf8_arg == NULL) {
3634 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3635 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3639 main_args [i] = utf8_arg;
3646 * mono_runtime_run_main:
3647 * @method: the method to start the application with (usually Main)
3648 * @argc: number of arguments from the command line
3649 * @argv: array of strings from the command line
3650 * @exc: excetption results
3652 * Execute a standard Main() method (argc/argv contains the
3653 * executable name). This method also sets the command line argument value
3654 * needed by System.Environment.
3659 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3663 MonoArray *args = NULL;
3664 MonoDomain *domain = mono_domain_get ();
3665 gchar *utf8_fullpath;
3666 MonoMethodSignature *sig;
3668 g_assert (method != NULL);
3670 mono_thread_set_main (mono_thread_current ());
3672 main_args = g_new0 (char*, argc);
3673 num_main_args = argc;
3675 if (!g_path_is_absolute (argv [0])) {
3676 gchar *basename = g_path_get_basename (argv [0]);
3677 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3681 utf8_fullpath = mono_utf8_from_external (fullpath);
3682 if(utf8_fullpath == NULL) {
3683 /* Printing the arg text will cause glib to
3684 * whinge about "Invalid UTF-8", but at least
3685 * its relevant, and shows the problem text
3688 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3689 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3696 utf8_fullpath = mono_utf8_from_external (argv[0]);
3697 if(utf8_fullpath == NULL) {
3698 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3699 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3704 main_args [0] = utf8_fullpath;
3706 for (i = 1; i < argc; ++i) {
3709 utf8_arg=mono_utf8_from_external (argv[i]);
3710 if(utf8_arg==NULL) {
3711 /* Ditto the comment about Invalid UTF-8 here */
3712 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3713 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3717 main_args [i] = utf8_arg;
3722 sig = mono_method_signature (method);
3724 g_print ("Unable to load Main method.\n");
3728 if (sig->param_count) {
3729 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3730 for (i = 0; i < argc; ++i) {
3731 /* The encodings should all work, given that
3732 * we've checked all these args for the
3735 gchar *str = mono_utf8_from_external (argv [i]);
3736 MonoString *arg = mono_string_new (domain, str);
3737 mono_array_setref (args, i, arg);
3741 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3744 mono_assembly_set_main (method->klass->image->assembly);
3746 return mono_runtime_exec_main (method, args, exc);
3750 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3752 static MonoMethod *serialize_method;
3757 if (!serialize_method) {
3758 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3759 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3762 if (!serialize_method) {
3767 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3771 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3779 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3781 static MonoMethod *deserialize_method;
3786 if (!deserialize_method) {
3787 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3788 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3790 if (!deserialize_method) {
3797 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3804 #ifndef DISABLE_REMOTING
3806 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3808 static MonoMethod *get_proxy_method;
3810 MonoDomain *domain = mono_domain_get ();
3811 MonoRealProxy *real_proxy;
3812 MonoReflectionType *reflection_type;
3813 MonoTransparentProxy *transparent_proxy;
3815 if (!get_proxy_method)
3816 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3818 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3820 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3821 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3823 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3824 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3827 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3831 return (MonoObject*) transparent_proxy;
3833 #endif /* DISABLE_REMOTING */
3836 * mono_object_xdomain_representation
3838 * @target_domain: a domain
3839 * @exc: pointer to a MonoObject*
3841 * Creates a representation of obj in the domain target_domain. This
3842 * is either a copy of obj arrived through via serialization and
3843 * deserialization or a proxy, depending on whether the object is
3844 * serializable or marshal by ref. obj must not be in target_domain.
3846 * If the object cannot be represented in target_domain, NULL is
3847 * returned and *exc is set to an appropriate exception.
3850 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3852 MonoObject *deserialized = NULL;
3853 gboolean failure = FALSE;
3857 #ifndef DISABLE_REMOTING
3858 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3859 deserialized = make_transparent_proxy (obj, &failure, exc);
3864 MonoDomain *domain = mono_domain_get ();
3865 MonoObject *serialized;
3867 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3868 serialized = serialize_object (obj, &failure, exc);
3869 mono_domain_set_internal_with_options (target_domain, FALSE);
3871 deserialized = deserialize_object (serialized, &failure, exc);
3872 if (domain != target_domain)
3873 mono_domain_set_internal_with_options (domain, FALSE);
3876 return deserialized;
3879 /* Used in call_unhandled_exception_delegate */
3881 create_unhandled_exception_eventargs (MonoObject *exc)
3885 MonoMethod *method = NULL;
3886 MonoBoolean is_terminating = TRUE;
3889 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3892 mono_class_init (klass);
3894 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3895 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3899 args [1] = &is_terminating;
3901 obj = mono_object_new (mono_domain_get (), klass);
3902 mono_runtime_invoke (method, obj, args, NULL);
3907 /* Used in mono_unhandled_exception */
3909 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3910 MonoObject *e = NULL;
3912 MonoDomain *current_domain = mono_domain_get ();
3914 if (domain != current_domain)
3915 mono_domain_set_internal_with_options (domain, FALSE);
3917 g_assert (domain == mono_object_domain (domain->domain));
3919 if (mono_object_domain (exc) != domain) {
3920 MonoObject *serialization_exc;
3922 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3924 if (serialization_exc) {
3926 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3929 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3930 "System.Runtime.Serialization", "SerializationException",
3931 "Could not serialize unhandled exception.");
3935 g_assert (mono_object_domain (exc) == domain);
3937 pa [0] = domain->domain;
3938 pa [1] = create_unhandled_exception_eventargs (exc);
3939 mono_runtime_delegate_invoke (delegate, pa, &e);
3941 if (domain != current_domain)
3942 mono_domain_set_internal_with_options (current_domain, FALSE);
3946 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3947 if (!mono_error_ok (&error)) {
3948 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3949 mono_error_cleanup (&error);
3951 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3957 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3960 * mono_runtime_unhandled_exception_policy_set:
3961 * @policy: the new policy
3963 * This is a VM internal routine.
3965 * Sets the runtime policy for handling unhandled exceptions.
3968 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3969 runtime_unhandled_exception_policy = policy;
3973 * mono_runtime_unhandled_exception_policy_get:
3975 * This is a VM internal routine.
3977 * Gets the runtime policy for handling unhandled exceptions.
3979 MonoRuntimeUnhandledExceptionPolicy
3980 mono_runtime_unhandled_exception_policy_get (void) {
3981 return runtime_unhandled_exception_policy;
3985 * mono_unhandled_exception:
3986 * @exc: exception thrown
3988 * This is a VM internal routine.
3990 * We call this function when we detect an unhandled exception
3991 * in the default domain.
3993 * It invokes the * UnhandledException event in AppDomain or prints
3994 * a warning to the console
3997 mono_unhandled_exception (MonoObject *exc)
3999 MonoDomain *current_domain = mono_domain_get ();
4000 MonoDomain *root_domain = mono_get_root_domain ();
4001 MonoClassField *field;
4002 MonoObject *current_appdomain_delegate;
4003 MonoObject *root_appdomain_delegate;
4005 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
4006 "UnhandledException");
4009 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4010 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4011 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4012 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4013 if (current_domain != root_domain) {
4014 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4016 current_appdomain_delegate = NULL;
4019 /* set exitcode only if we will abort the process */
4020 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4022 mono_environment_exitcode_set (1);
4023 mono_print_unhandled_exception (exc);
4025 if (root_appdomain_delegate) {
4026 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4028 if (current_appdomain_delegate) {
4029 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4036 * mono_runtime_exec_managed_code:
4037 * @domain: Application domain
4038 * @main_func: function to invoke from the execution thread
4039 * @main_args: parameter to the main_func
4041 * Launch a new thread to execute a function
4043 * main_func is called back from the thread with main_args as the
4044 * parameter. The callback function is expected to start Main()
4045 * eventually. This function then waits for all managed threads to
4047 * It is not necesseray anymore to execute managed code in a subthread,
4048 * so this function should not be used anymore by default: just
4049 * execute the code and then call mono_thread_manage ().
4052 mono_runtime_exec_managed_code (MonoDomain *domain,
4053 MonoMainThreadFunc main_func,
4056 mono_thread_create (domain, main_func, main_args);
4058 mono_thread_manage ();
4062 * Execute a standard Main() method (args doesn't contain the
4066 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4071 MonoCustomAttrInfo* cinfo;
4072 gboolean has_stathread_attribute;
4073 MonoInternalThread* thread = mono_thread_internal_current ();
4079 domain = mono_object_domain (args);
4080 if (!domain->entry_assembly) {
4082 MonoAssembly *assembly;
4084 assembly = method->klass->image->assembly;
4085 domain->entry_assembly = assembly;
4086 /* Domains created from another domain already have application_base and configuration_file set */
4087 if (domain->setup->application_base == NULL) {
4088 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4091 if (domain->setup->configuration_file == NULL) {
4092 str = g_strconcat (assembly->image->name, ".config", NULL);
4093 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4095 mono_set_private_bin_path_from_config (domain);
4099 cinfo = mono_custom_attrs_from_method (method);
4101 static MonoClass *stathread_attribute = NULL;
4102 if (!stathread_attribute)
4103 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4104 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4106 mono_custom_attrs_free (cinfo);
4108 has_stathread_attribute = FALSE;
4110 if (has_stathread_attribute) {
4111 thread->apartment_state = ThreadApartmentState_STA;
4113 thread->apartment_state = ThreadApartmentState_MTA;
4115 mono_thread_init_apartment_state ();
4117 /* FIXME: check signature of method */
4118 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4120 res = mono_runtime_invoke (method, NULL, pa, exc);
4122 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4126 mono_environment_exitcode_set (rval);
4128 mono_runtime_invoke (method, NULL, pa, exc);
4132 /* If the return type of Main is void, only
4133 * set the exitcode if an exception was thrown
4134 * (we don't want to blow away an
4135 * explicitly-set exit code)
4138 mono_environment_exitcode_set (rval);
4146 * mono_install_runtime_invoke:
4147 * @func: Function to install
4149 * This is a VM internal routine
4152 mono_install_runtime_invoke (MonoInvokeFunc func)
4154 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4159 * mono_runtime_invoke_array:
4160 * @method: method to invoke
4161 * @obJ: object instance
4162 * @params: arguments to the method
4163 * @exc: exception information.
4165 * Invokes the method represented by @method on the object @obj.
4167 * obj is the 'this' pointer, it should be NULL for static
4168 * methods, a MonoObject* for object instances and a pointer to
4169 * the value type for value types.
4171 * The params array contains the arguments to the method with the
4172 * same convention: MonoObject* pointers for object instances and
4173 * pointers to the value type otherwise. The _invoke_array
4174 * variant takes a C# object[] as the params argument (MonoArray
4175 * *params): in this case the value types are boxed inside the
4176 * respective reference representation.
4178 * From unmanaged code you'll usually use the
4179 * mono_runtime_invoke() variant.
4181 * Note that this function doesn't handle virtual methods for
4182 * you, it will exec the exact method you pass: we still need to
4183 * expose a function to lookup the derived class implementation
4184 * of a virtual method (there are examples of this in the code,
4187 * You can pass NULL as the exc argument if you don't want to
4188 * catch exceptions, otherwise, *exc will be set to the exception
4189 * thrown, if any. if an exception is thrown, you can't use the
4190 * MonoObject* result from the function.
4192 * If the method returns a value type, it is boxed in an object
4196 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4199 MonoMethodSignature *sig = mono_method_signature (method);
4200 gpointer *pa = NULL;
4203 gboolean has_byref_nullables = FALSE;
4205 if (NULL != params) {
4206 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4207 for (i = 0; i < mono_array_length (params); i++) {
4208 MonoType *t = sig->params [i];
4214 case MONO_TYPE_BOOLEAN:
4217 case MONO_TYPE_CHAR:
4226 case MONO_TYPE_VALUETYPE:
4227 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4228 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4229 pa [i] = mono_array_get (params, MonoObject*, i);
4231 has_byref_nullables = TRUE;
4233 /* MS seems to create the objects if a null is passed in */
4234 if (!mono_array_get (params, MonoObject*, i))
4235 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4239 * We can't pass the unboxed vtype byref to the callee, since
4240 * that would mean the callee would be able to modify boxed
4241 * primitive types. So we (and MS) make a copy of the boxed
4242 * object, pass that to the callee, and replace the original
4243 * boxed object in the arg array with the copy.
4245 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4246 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4247 mono_array_setref (params, i, copy);
4250 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4253 case MONO_TYPE_STRING:
4254 case MONO_TYPE_OBJECT:
4255 case MONO_TYPE_CLASS:
4256 case MONO_TYPE_ARRAY:
4257 case MONO_TYPE_SZARRAY:
4259 pa [i] = mono_array_addr (params, MonoObject*, i);
4260 // FIXME: I need to check this code path
4262 pa [i] = mono_array_get (params, MonoObject*, i);
4264 case MONO_TYPE_GENERICINST:
4266 t = &t->data.generic_class->container_class->this_arg;
4268 t = &t->data.generic_class->container_class->byval_arg;
4270 case MONO_TYPE_PTR: {
4273 /* The argument should be an IntPtr */
4274 arg = mono_array_get (params, MonoObject*, i);
4278 g_assert (arg->vtable->klass == mono_defaults.int_class);
4279 pa [i] = ((MonoIntPtr*)arg)->m_value;
4284 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4289 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4292 if (mono_class_is_nullable (method->klass)) {
4293 /* Need to create a boxed vtype instead */
4299 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4303 obj = mono_object_new (mono_domain_get (), method->klass);
4304 g_assert (obj); /*maybe we should raise a TLE instead?*/
4305 #ifndef DISABLE_REMOTING
4306 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4307 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4310 if (method->klass->valuetype)
4311 o = mono_object_unbox (obj);
4314 } else if (method->klass->valuetype) {
4315 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4318 mono_runtime_invoke (method, o, pa, exc);
4321 if (mono_class_is_nullable (method->klass)) {
4322 MonoObject *nullable;
4324 /* Convert the unboxed vtype into a Nullable structure */
4325 nullable = mono_object_new (mono_domain_get (), method->klass);
4327 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4328 obj = mono_object_unbox (nullable);
4331 /* obj must be already unboxed if needed */
4332 res = mono_runtime_invoke (method, obj, pa, exc);
4334 if (sig->ret->type == MONO_TYPE_PTR) {
4335 MonoClass *pointer_class;
4336 static MonoMethod *box_method;
4338 MonoObject *box_exc;
4341 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4342 * convert it to a Pointer object.
4344 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4346 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4348 g_assert (res->vtable->klass == mono_defaults.int_class);
4349 box_args [0] = ((MonoIntPtr*)res)->m_value;
4350 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4351 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4352 g_assert (!box_exc);
4355 if (has_byref_nullables) {
4357 * The runtime invoke wrapper already converted byref nullables back,
4358 * and stored them in pa, we just need to copy them back to the
4361 for (i = 0; i < mono_array_length (params); i++) {
4362 MonoType *t = sig->params [i];
4364 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4365 mono_array_setref (params, i, pa [i]);
4374 arith_overflow (void)
4376 mono_raise_exception (mono_get_exception_overflow ());
4380 * mono_object_allocate:
4381 * @size: number of bytes to allocate
4383 * This is a very simplistic routine until we have our GC-aware
4386 * Returns: an allocated object of size @size, or NULL on failure.
4388 static inline void *
4389 mono_object_allocate (size_t size, MonoVTable *vtable)
4392 ALLOC_OBJECT (o, vtable, size);
4398 * mono_object_allocate_ptrfree:
4399 * @size: number of bytes to allocate
4401 * Note that the memory allocated is not zeroed.
4402 * Returns: an allocated object of size @size, or NULL on failure.
4404 static inline void *
4405 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4408 ALLOC_PTRFREE (o, vtable, size);
4412 static inline void *
4413 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4416 ALLOC_TYPED (o, size, vtable);
4423 * @klass: the class of the object that we want to create
4425 * Returns: a newly created object whose definition is
4426 * looked up using @klass. This will not invoke any constructors,
4427 * so the consumer of this routine has to invoke any constructors on
4428 * its own to initialize the object.
4430 * It returns NULL on failure.
4433 mono_object_new (MonoDomain *domain, MonoClass *klass)
4437 MONO_ARCH_SAVE_REGS;
4438 vtable = mono_class_vtable (domain, klass);
4441 return mono_object_new_specific (vtable);
4445 * mono_object_new_pinned:
4447 * Same as mono_object_new, but the returned object will be pinned.
4448 * For SGEN, these objects will only be freed at appdomain unload.
4451 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4455 MONO_ARCH_SAVE_REGS;
4456 vtable = mono_class_vtable (domain, klass);
4461 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4463 return mono_object_new_specific (vtable);
4468 * mono_object_new_specific:
4469 * @vtable: the vtable of the object that we want to create
4471 * Returns: A newly created object with class and domain specified
4475 mono_object_new_specific (MonoVTable *vtable)
4479 MONO_ARCH_SAVE_REGS;
4481 /* check for is_com_object for COM Interop */
4482 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4485 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4488 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4491 mono_class_init (klass);
4493 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4495 vtable->domain->create_proxy_for_type_method = im;
4498 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4500 o = mono_runtime_invoke (im, NULL, pa, NULL);
4501 if (o != NULL) return o;
4504 return mono_object_new_alloc_specific (vtable);
4508 mono_object_new_alloc_specific (MonoVTable *vtable)
4512 if (!vtable->klass->has_references) {
4513 o = mono_object_new_ptrfree (vtable);
4514 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4515 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4517 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4518 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4520 if (G_UNLIKELY (vtable->klass->has_finalize))
4521 mono_object_register_finalizer (o);
4523 if (G_UNLIKELY (profile_allocs))
4524 mono_profiler_allocation (o, vtable->klass);
4529 mono_object_new_fast (MonoVTable *vtable)
4532 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4537 mono_object_new_ptrfree (MonoVTable *vtable)
4540 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4541 #if NEED_TO_ZERO_PTRFREE
4542 /* an inline memset is much faster for the common vcase of small objects
4543 * note we assume the allocated size is a multiple of sizeof (void*).
4545 if (vtable->klass->instance_size < 128) {
4547 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4548 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4554 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4561 mono_object_new_ptrfree_box (MonoVTable *vtable)
4564 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4565 /* the object will be boxed right away, no need to memzero it */
4570 * mono_class_get_allocation_ftn:
4572 * @for_box: the object will be used for boxing
4573 * @pass_size_in_words:
4575 * Return the allocation function appropriate for the given class.
4579 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4581 *pass_size_in_words = FALSE;
4583 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4584 profile_allocs = FALSE;
4586 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4587 return mono_object_new_specific;
4589 if (!vtable->klass->has_references) {
4590 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4592 return mono_object_new_ptrfree_box;
4593 return mono_object_new_ptrfree;
4596 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4598 return mono_object_new_fast;
4601 * FIXME: This is actually slower than mono_object_new_fast, because
4602 * of the overhead of parameter passing.
4605 *pass_size_in_words = TRUE;
4606 #ifdef GC_REDIRECT_TO_LOCAL
4607 return GC_local_gcj_fast_malloc;
4609 return GC_gcj_fast_malloc;
4614 return mono_object_new_specific;
4618 * mono_object_new_from_token:
4619 * @image: Context where the type_token is hosted
4620 * @token: a token of the type that we want to create
4622 * Returns: A newly created object whose definition is
4623 * looked up using @token in the @image image
4626 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4631 class = mono_class_get_checked (image, token, &error);
4632 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4634 return mono_object_new (domain, class);
4639 * mono_object_clone:
4640 * @obj: the object to clone
4642 * Returns: A newly created object who is a shallow copy of @obj
4645 mono_object_clone (MonoObject *obj)
4648 int size = obj->vtable->klass->instance_size;
4650 if (obj->vtable->klass->rank)
4651 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4653 o = mono_object_allocate (size, obj->vtable);
4655 if (obj->vtable->klass->has_references) {
4656 mono_gc_wbarrier_object_copy (o, obj);
4658 int size = obj->vtable->klass->instance_size;
4659 /* do not copy the sync state */
4660 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4662 if (G_UNLIKELY (profile_allocs))
4663 mono_profiler_allocation (o, obj->vtable->klass);
4665 if (obj->vtable->klass->has_finalize)
4666 mono_object_register_finalizer (o);
4671 * mono_array_full_copy:
4672 * @src: source array to copy
4673 * @dest: destination array
4675 * Copies the content of one array to another with exactly the same type and size.
4678 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4681 MonoClass *klass = src->obj.vtable->klass;
4683 MONO_ARCH_SAVE_REGS;
4685 g_assert (klass == dest->obj.vtable->klass);
4687 size = mono_array_length (src);
4688 g_assert (size == mono_array_length (dest));
4689 size *= mono_array_element_size (klass);
4691 if (klass->element_class->valuetype) {
4692 if (klass->element_class->has_references)
4693 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4695 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4697 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4700 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4705 * mono_array_clone_in_domain:
4706 * @domain: the domain in which the array will be cloned into
4707 * @array: the array to clone
4709 * This routine returns a copy of the array that is hosted on the
4710 * specified MonoDomain.
4713 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4718 MonoClass *klass = array->obj.vtable->klass;
4720 MONO_ARCH_SAVE_REGS;
4722 if (array->bounds == NULL) {
4723 size = mono_array_length (array);
4724 o = mono_array_new_full (domain, klass, &size, NULL);
4726 size *= mono_array_element_size (klass);
4728 if (klass->element_class->valuetype) {
4729 if (klass->element_class->has_references)
4730 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4732 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4734 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4737 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4742 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4743 size = mono_array_element_size (klass);
4744 for (i = 0; i < klass->rank; ++i) {
4745 sizes [i] = array->bounds [i].length;
4746 size *= array->bounds [i].length;
4747 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4749 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4751 if (klass->element_class->valuetype) {
4752 if (klass->element_class->has_references)
4753 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4755 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4757 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4760 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4768 * @array: the array to clone
4770 * Returns: A newly created array who is a shallow copy of @array
4773 mono_array_clone (MonoArray *array)
4775 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4778 /* helper macros to check for overflow when calculating the size of arrays */
4779 #ifdef MONO_BIG_ARRAYS
4780 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4781 #define MYGUINT_MAX MYGUINT64_MAX
4782 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4783 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4784 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4785 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4786 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4788 #define MYGUINT32_MAX 4294967295U
4789 #define MYGUINT_MAX MYGUINT32_MAX
4790 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4791 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4792 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4793 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4794 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4798 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4802 byte_len = mono_array_element_size (class);
4803 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4806 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4808 byte_len += sizeof (MonoArray);
4816 * mono_array_new_full:
4817 * @domain: domain where the object is created
4818 * @array_class: array class
4819 * @lengths: lengths for each dimension in the array
4820 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4822 * This routine creates a new array objects with the given dimensions,
4823 * lower bounds and type.
4826 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4828 uintptr_t byte_len = 0, len, bounds_size;
4831 MonoArrayBounds *bounds;
4835 if (!array_class->inited)
4836 mono_class_init (array_class);
4840 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4841 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4843 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4847 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4849 for (i = 0; i < array_class->rank; ++i) {
4850 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4852 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4853 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4858 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4859 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4863 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4864 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4865 byte_len = (byte_len + 3) & ~3;
4866 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4867 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4868 byte_len += bounds_size;
4871 * Following three lines almost taken from mono_object_new ():
4872 * they need to be kept in sync.
4874 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4875 #ifndef HAVE_SGEN_GC
4876 if (!array_class->has_references) {
4877 o = mono_object_allocate_ptrfree (byte_len, vtable);
4878 #if NEED_TO_ZERO_PTRFREE
4879 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4881 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4882 o = mono_object_allocate_spec (byte_len, vtable);
4884 o = mono_object_allocate (byte_len, vtable);
4887 array = (MonoArray*)o;
4888 array->max_length = len;
4891 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4892 array->bounds = bounds;
4896 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4898 o = mono_gc_alloc_vector (vtable, byte_len, len);
4899 array = (MonoArray*)o;
4901 bounds = array->bounds;
4905 for (i = 0; i < array_class->rank; ++i) {
4906 bounds [i].length = lengths [i];
4908 bounds [i].lower_bound = lower_bounds [i];
4912 if (G_UNLIKELY (profile_allocs))
4913 mono_profiler_allocation (o, array_class);
4920 * @domain: domain where the object is created
4921 * @eclass: element class
4922 * @n: number of array elements
4924 * This routine creates a new szarray with @n elements of type @eclass.
4927 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4931 MONO_ARCH_SAVE_REGS;
4933 ac = mono_array_class_get (eclass, 1);
4936 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4940 * mono_array_new_specific:
4941 * @vtable: a vtable in the appropriate domain for an initialized class
4942 * @n: number of array elements
4944 * This routine is a fast alternative to mono_array_new() for code which
4945 * can be sure about the domain it operates in.
4948 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4954 MONO_ARCH_SAVE_REGS;
4956 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4961 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4962 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4965 #ifndef HAVE_SGEN_GC
4966 if (!vtable->klass->has_references) {
4967 o = mono_object_allocate_ptrfree (byte_len, vtable);
4968 #if NEED_TO_ZERO_PTRFREE
4969 ((MonoArray*)o)->bounds = NULL;
4970 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4972 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4973 o = mono_object_allocate_spec (byte_len, vtable);
4975 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4976 o = mono_object_allocate (byte_len, vtable);
4979 ao = (MonoArray *)o;
4982 o = mono_gc_alloc_vector (vtable, byte_len, n);
4986 if (G_UNLIKELY (profile_allocs))
4987 mono_profiler_allocation (o, vtable->klass);
4993 * mono_string_new_utf16:
4994 * @text: a pointer to an utf16 string
4995 * @len: the length of the string
4997 * Returns: A newly created string object which contains @text.
5000 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5004 s = mono_string_new_size (domain, len);
5005 g_assert (s != NULL);
5007 memcpy (mono_string_chars (s), text, len * 2);
5013 * mono_string_new_utf32:
5014 * @text: a pointer to an utf32 string
5015 * @len: the length of the string
5017 * Returns: A newly created string object which contains @text.
5020 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5023 mono_unichar2 *utf16_output = NULL;
5024 gint32 utf16_len = 0;
5025 GError *error = NULL;
5026 glong items_written;
5028 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5031 g_error_free (error);
5033 while (utf16_output [utf16_len]) utf16_len++;
5035 s = mono_string_new_size (domain, utf16_len);
5036 g_assert (s != NULL);
5038 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5040 g_free (utf16_output);
5046 * mono_string_new_size:
5047 * @text: a pointer to an utf16 string
5048 * @len: the length of the string
5050 * Returns: A newly created string object of @len
5053 mono_string_new_size (MonoDomain *domain, gint32 len)
5059 /* check for overflow */
5060 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 2) / 2))
5061 mono_gc_out_of_memory (-1);
5063 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5064 g_assert (size > 0);
5066 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5069 #ifndef HAVE_SGEN_GC
5070 s = mono_object_allocate_ptrfree (size, vtable);
5074 s = mono_gc_alloc_string (vtable, size, len);
5076 #if NEED_TO_ZERO_PTRFREE
5079 if (G_UNLIKELY (profile_allocs))
5080 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5086 * mono_string_new_len:
5087 * @text: a pointer to an utf8 string
5088 * @length: number of bytes in @text to consider
5090 * Returns: A newly created string object which contains @text.
5093 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5095 GError *error = NULL;
5096 MonoString *o = NULL;
5098 glong items_written;
5100 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5103 o = mono_string_new_utf16 (domain, ut, items_written);
5105 g_error_free (error);
5114 * @text: a pointer to an utf8 string
5116 * Returns: A newly created string object which contains @text.
5119 mono_string_new (MonoDomain *domain, const char *text)
5121 GError *error = NULL;
5122 MonoString *o = NULL;
5124 glong items_written;
5129 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5132 o = mono_string_new_utf16 (domain, ut, items_written);
5134 g_error_free (error);
5137 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5142 MonoString *o = NULL;
5144 if (!g_utf8_validate (text, -1, &end))
5147 len = g_utf8_strlen (text, -1);
5148 o = mono_string_new_size (domain, len);
5149 str = mono_string_chars (o);
5151 while (text < end) {
5152 *str++ = g_utf8_get_char (text);
5153 text = g_utf8_next_char (text);
5160 * mono_string_new_wrapper:
5161 * @text: pointer to utf8 characters.
5163 * Helper function to create a string object from @text in the current domain.
5166 mono_string_new_wrapper (const char *text)
5168 MonoDomain *domain = mono_domain_get ();
5170 MONO_ARCH_SAVE_REGS;
5173 return mono_string_new (domain, text);
5180 * @class: the class of the value
5181 * @value: a pointer to the unboxed data
5183 * Returns: A newly created object which contains @value.
5186 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5192 g_assert (class->valuetype);
5193 if (mono_class_is_nullable (class))
5194 return mono_nullable_box (value, class);
5196 vtable = mono_class_vtable (domain, class);
5199 size = mono_class_instance_size (class);
5200 res = mono_object_new_alloc_specific (vtable);
5201 if (G_UNLIKELY (profile_allocs))
5202 mono_profiler_allocation (res, class);
5204 size = size - sizeof (MonoObject);
5207 g_assert (size == mono_class_value_size (class, NULL));
5208 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5210 #if NO_UNALIGNED_ACCESS
5211 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5215 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5218 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5221 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5224 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5227 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5231 if (class->has_finalize)
5232 mono_object_register_finalizer (res);
5238 * @dest: destination pointer
5239 * @src: source pointer
5240 * @klass: a valuetype class
5242 * Copy a valuetype from @src to @dest. This function must be used
5243 * when @klass contains references fields.
5246 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5248 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5252 * mono_value_copy_array:
5253 * @dest: destination array
5254 * @dest_idx: index in the @dest array
5255 * @src: source pointer
5256 * @count: number of items
5258 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5259 * This function must be used when @klass contains references fields.
5260 * Overlap is handled.
5263 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5265 int size = mono_array_element_size (dest->obj.vtable->klass);
5266 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5267 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5268 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5272 * mono_object_get_domain:
5273 * @obj: object to query
5275 * Returns: the MonoDomain where the object is hosted
5278 mono_object_get_domain (MonoObject *obj)
5280 return mono_object_domain (obj);
5284 * mono_object_get_class:
5285 * @obj: object to query
5287 * Returns: the MonOClass of the object.
5290 mono_object_get_class (MonoObject *obj)
5292 return mono_object_class (obj);
5295 * mono_object_get_size:
5296 * @o: object to query
5298 * Returns: the size, in bytes, of @o
5301 mono_object_get_size (MonoObject* o)
5303 MonoClass* klass = mono_object_class (o);
5304 if (klass == mono_defaults.string_class) {
5305 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5306 } else if (o->vtable->rank) {
5307 MonoArray *array = (MonoArray*)o;
5308 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5309 if (array->bounds) {
5312 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5316 return mono_class_instance_size (klass);
5321 * mono_object_unbox:
5322 * @obj: object to unbox
5324 * Returns: a pointer to the start of the valuetype boxed in this
5327 * This method will assert if the object passed is not a valuetype.
5330 mono_object_unbox (MonoObject *obj)
5332 /* add assert for valuetypes? */
5333 g_assert (obj->vtable->klass->valuetype);
5334 return ((char*)obj) + sizeof (MonoObject);
5338 * mono_object_isinst:
5340 * @klass: a pointer to a class
5342 * Returns: @obj if @obj is derived from @klass
5345 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5348 mono_class_init (klass);
5350 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5351 return mono_object_isinst_mbyref (obj, klass);
5356 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5360 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5369 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5370 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5374 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5375 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5378 MonoClass *oklass = vt->klass;
5379 if (mono_class_is_transparent_proxy (oklass))
5380 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5382 mono_class_setup_supertypes (klass);
5383 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5386 #ifndef DISABLE_REMOTING
5387 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5389 MonoDomain *domain = mono_domain_get ();
5391 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5392 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5393 MonoMethod *im = NULL;
5396 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5397 im = mono_object_get_virtual_method (rp, im);
5400 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5403 res = mono_runtime_invoke (im, rp, pa, NULL);
5405 if (*(MonoBoolean *) mono_object_unbox(res)) {
5406 /* Update the vtable of the remote type, so it can safely cast to this new type */
5407 mono_upgrade_remote_class (domain, obj, klass);
5411 #endif /* DISABLE_REMOTING */
5416 * mono_object_castclass_mbyref:
5418 * @klass: a pointer to a class
5420 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5423 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5425 if (!obj) return NULL;
5426 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5428 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5430 "InvalidCastException"));
5435 MonoDomain *orig_domain;
5441 str_lookup (MonoDomain *domain, gpointer user_data)
5443 LDStrInfo *info = user_data;
5444 if (info->res || domain == info->orig_domain)
5446 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5452 mono_string_get_pinned (MonoString *str)
5456 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5457 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5459 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5460 news->length = mono_string_length (str);
5466 #define mono_string_get_pinned(str) (str)
5470 mono_string_is_interned_lookup (MonoString *str, int insert)
5472 MonoGHashTable *ldstr_table;
5476 domain = ((MonoObject *)str)->vtable->domain;
5477 ldstr_table = domain->ldstr_table;
5479 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5484 str = mono_string_get_pinned (str);
5486 mono_g_hash_table_insert (ldstr_table, str, str);
5490 LDStrInfo ldstr_info;
5491 ldstr_info.orig_domain = domain;
5492 ldstr_info.ins = str;
5493 ldstr_info.res = NULL;
5495 mono_domain_foreach (str_lookup, &ldstr_info);
5496 if (ldstr_info.res) {
5498 * the string was already interned in some other domain:
5499 * intern it in the current one as well.
5501 mono_g_hash_table_insert (ldstr_table, str, str);
5511 * mono_string_is_interned:
5512 * @o: String to probe
5514 * Returns whether the string has been interned.
5517 mono_string_is_interned (MonoString *o)
5519 return mono_string_is_interned_lookup (o, FALSE);
5523 * mono_string_intern:
5524 * @o: String to intern
5526 * Interns the string passed.
5527 * Returns: The interned string.
5530 mono_string_intern (MonoString *str)
5532 return mono_string_is_interned_lookup (str, TRUE);
5537 * @domain: the domain where the string will be used.
5538 * @image: a metadata context
5539 * @idx: index into the user string table.
5541 * Implementation for the ldstr opcode.
5542 * Returns: a loaded string from the @image/@idx combination.
5545 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5547 MONO_ARCH_SAVE_REGS;
5549 if (image->dynamic) {
5550 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5553 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5554 return NULL; /*FIXME we should probably be raising an exception here*/
5555 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5560 * mono_ldstr_metadata_sig
5561 * @domain: the domain for the string
5562 * @sig: the signature of a metadata string
5564 * Returns: a MonoString for a string stored in the metadata
5567 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5569 const char *str = sig;
5570 MonoString *o, *interned;
5573 len2 = mono_metadata_decode_blob_size (str, &str);
5576 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5577 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5580 guint16 *p2 = (guint16*)mono_string_chars (o);
5581 for (i = 0; i < len2; ++i) {
5582 *p2 = GUINT16_FROM_LE (*p2);
5588 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5590 /* o will get garbage collected */
5594 o = mono_string_get_pinned (o);
5596 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5603 * mono_string_to_utf8:
5604 * @s: a System.String
5606 * Returns the UTF8 representation for @s.
5607 * The resulting buffer needs to be freed with mono_free().
5609 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5612 mono_string_to_utf8 (MonoString *s)
5615 char *result = mono_string_to_utf8_checked (s, &error);
5617 if (!mono_error_ok (&error))
5618 mono_error_raise_exception (&error);
5623 * mono_string_to_utf8_checked:
5624 * @s: a System.String
5625 * @error: a MonoError.
5627 * Converts a MonoString to its UTF8 representation. May fail; check
5628 * @error to determine whether the conversion was successful.
5629 * The resulting buffer should be freed with mono_free().
5632 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5636 GError *gerror = NULL;
5638 mono_error_init (error);
5644 return g_strdup ("");
5646 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5648 mono_error_set_argument (error, "string", "%s", gerror->message);
5649 g_error_free (gerror);
5652 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5653 if (s->length > written) {
5654 /* allocate the total length and copy the part of the string that has been converted */
5655 char *as2 = g_malloc0 (s->length);
5656 memcpy (as2, as, written);
5665 * mono_string_to_utf8_ignore:
5668 * Converts a MonoString to its UTF8 representation. Will ignore
5669 * invalid surrogate pairs.
5670 * The resulting buffer should be freed with mono_free().
5674 mono_string_to_utf8_ignore (MonoString *s)
5683 return g_strdup ("");
5685 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5687 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5688 if (s->length > written) {
5689 /* allocate the total length and copy the part of the string that has been converted */
5690 char *as2 = g_malloc0 (s->length);
5691 memcpy (as2, as, written);
5700 * mono_string_to_utf8_image_ignore:
5701 * @s: a System.String
5703 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5706 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5708 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5712 * mono_string_to_utf8_mp_ignore:
5713 * @s: a System.String
5715 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5718 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5720 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5725 * mono_string_to_utf16:
5728 * Return an null-terminated array of the utf-16 chars
5729 * contained in @s. The result must be freed with g_free().
5730 * This is a temporary helper until our string implementation
5731 * is reworked to always include the null terminating char.
5734 mono_string_to_utf16 (MonoString *s)
5741 as = g_malloc ((s->length * 2) + 2);
5742 as [(s->length * 2)] = '\0';
5743 as [(s->length * 2) + 1] = '\0';
5746 return (gunichar2 *)(as);
5749 memcpy (as, mono_string_chars(s), s->length * 2);
5750 return (gunichar2 *)(as);
5754 * mono_string_to_utf32:
5757 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5758 * contained in @s. The result must be freed with g_free().
5761 mono_string_to_utf32 (MonoString *s)
5763 mono_unichar4 *utf32_output = NULL;
5764 GError *error = NULL;
5765 glong items_written;
5770 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5773 g_error_free (error);
5775 return utf32_output;
5779 * mono_string_from_utf16:
5780 * @data: the UTF16 string (LPWSTR) to convert
5782 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5784 * Returns: a MonoString.
5787 mono_string_from_utf16 (gunichar2 *data)
5789 MonoDomain *domain = mono_domain_get ();
5795 while (data [len]) len++;
5797 return mono_string_new_utf16 (domain, data, len);
5801 * mono_string_from_utf32:
5802 * @data: the UTF32 string (LPWSTR) to convert
5804 * Converts a UTF32 (UCS-4)to a MonoString.
5806 * Returns: a MonoString.
5809 mono_string_from_utf32 (mono_unichar4 *data)
5811 MonoString* result = NULL;
5812 mono_unichar2 *utf16_output = NULL;
5813 GError *error = NULL;
5814 glong items_written;
5820 while (data [len]) len++;
5822 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5825 g_error_free (error);
5827 result = mono_string_from_utf16 (utf16_output);
5828 g_free (utf16_output);
5833 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5840 r = mono_string_to_utf8_ignore (s);
5842 r = mono_string_to_utf8_checked (s, error);
5843 if (!mono_error_ok (error))
5850 len = strlen (r) + 1;
5852 mp_s = mono_mempool_alloc (mp, len);
5854 mp_s = mono_image_alloc (image, len);
5856 memcpy (mp_s, r, len);
5864 * mono_string_to_utf8_image:
5865 * @s: a System.String
5867 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5870 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5872 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5876 * mono_string_to_utf8_mp:
5877 * @s: a System.String
5879 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5882 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5884 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5888 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5891 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5893 eh_callbacks = *cbs;
5896 MonoRuntimeExceptionHandlingCallbacks *
5897 mono_get_eh_callbacks (void)
5899 return &eh_callbacks;
5903 * mono_raise_exception:
5904 * @ex: exception object
5906 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5909 mono_raise_exception (MonoException *ex)
5912 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5913 * that will cause gcc to omit the function epilog, causing problems when
5914 * the JIT tries to walk the stack, since the return address on the stack
5915 * will point into the next function in the executable, not this one.
5917 eh_callbacks.mono_raise_exception (ex);
5921 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5923 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5927 * mono_wait_handle_new:
5928 * @domain: Domain where the object will be created
5929 * @handle: Handle for the wait handle
5931 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5934 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5936 MonoWaitHandle *res;
5937 gpointer params [1];
5938 static MonoMethod *handle_set;
5940 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5942 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5944 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5946 params [0] = &handle;
5947 mono_runtime_invoke (handle_set, res, params, NULL);
5953 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5955 static MonoClassField *f_os_handle;
5956 static MonoClassField *f_safe_handle;
5958 if (!f_os_handle && !f_safe_handle) {
5959 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5960 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5965 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5969 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5976 mono_runtime_capture_context (MonoDomain *domain)
5978 RuntimeInvokeFunction runtime_invoke;
5980 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5981 MonoMethod *method = mono_get_context_capture_method ();
5982 MonoMethod *wrapper;
5985 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5986 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5987 domain->capture_context_method = mono_compile_method (method);
5990 runtime_invoke = domain->capture_context_runtime_invoke;
5992 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5995 * mono_async_result_new:
5996 * @domain:domain where the object will be created.
5997 * @handle: wait handle.
5998 * @state: state to pass to AsyncResult
5999 * @data: C closure data.
6001 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6002 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6006 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6008 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6009 MonoObject *context = mono_runtime_capture_context (domain);
6010 /* we must capture the execution context from the original thread */
6012 MONO_OBJECT_SETREF (res, execution_context, context);
6013 /* note: result may be null if the flow is suppressed */
6017 MONO_OBJECT_SETREF (res, object_data, object_data);
6018 MONO_OBJECT_SETREF (res, async_state, state);
6020 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6022 res->sync_completed = FALSE;
6023 res->completed = FALSE;
6029 mono_message_init (MonoDomain *domain,
6030 MonoMethodMessage *this,
6031 MonoReflectionMethod *method,
6032 MonoArray *out_args)
6034 static MonoClass *object_array_klass;
6035 static MonoClass *byte_array_klass;
6036 static MonoClass *string_array_klass;
6037 MonoMethodSignature *sig = mono_method_signature (method->method);
6043 if (!object_array_klass) {
6046 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6048 byte_array_klass = klass;
6050 klass = mono_array_class_get (mono_defaults.string_class, 1);
6052 string_array_klass = klass;
6054 klass = mono_array_class_get (mono_defaults.object_class, 1);
6057 mono_atomic_store_release (&object_array_klass, klass);
6060 MONO_OBJECT_SETREF (this, method, method);
6062 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6063 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6064 this->async_result = NULL;
6065 this->call_type = CallType_Sync;
6067 names = g_new (char *, sig->param_count);
6068 mono_method_get_param_names (method->method, (const char **) names);
6069 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6071 for (i = 0; i < sig->param_count; i++) {
6072 name = mono_string_new (domain, names [i]);
6073 mono_array_setref (this->names, i, name);
6077 for (i = 0, j = 0; i < sig->param_count; i++) {
6078 if (sig->params [i]->byref) {
6080 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6081 mono_array_setref (this->args, i, arg);
6085 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6089 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6092 mono_array_set (this->arg_types, guint8, i, arg_type);
6096 #ifndef DISABLE_REMOTING
6098 * mono_remoting_invoke:
6099 * @real_proxy: pointer to a RealProxy object
6100 * @msg: The MonoMethodMessage to execute
6101 * @exc: used to store exceptions
6102 * @out_args: used to store output arguments
6104 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6105 * IMessage interface and it is not trivial to extract results from there. So
6106 * we call an helper method PrivateInvoke instead of calling
6107 * RealProxy::Invoke() directly.
6109 * Returns: the result object.
6112 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6113 MonoObject **exc, MonoArray **out_args)
6115 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6118 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6121 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6123 real_proxy->vtable->domain->private_invoke_method = im;
6126 pa [0] = real_proxy;
6131 return mono_runtime_invoke (im, NULL, pa, exc);
6136 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6137 MonoObject **exc, MonoArray **out_args)
6139 static MonoClass *object_array_klass;
6142 MonoMethodSignature *sig;
6144 int i, j, outarg_count = 0;
6146 #ifndef DISABLE_REMOTING
6147 if (target && mono_object_is_transparent_proxy (target)) {
6148 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6149 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6150 target = tp->rp->unwrapped_server;
6152 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6157 domain = mono_domain_get ();
6158 method = msg->method->method;
6159 sig = mono_method_signature (method);
6161 for (i = 0; i < sig->param_count; i++) {
6162 if (sig->params [i]->byref)
6166 if (!object_array_klass) {
6169 klass = mono_array_class_get (mono_defaults.object_class, 1);
6172 mono_memory_barrier ();
6173 object_array_klass = klass;
6176 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6177 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6180 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6182 for (i = 0, j = 0; i < sig->param_count; i++) {
6183 if (sig->params [i]->byref) {
6185 arg = mono_array_get (msg->args, gpointer, i);
6186 mono_array_setref (*out_args, j, arg);
6195 * mono_object_to_string:
6197 * @exc: Any exception thrown by ToString (). May be NULL.
6199 * Returns: the result of calling ToString () on an object.
6202 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6204 static MonoMethod *to_string = NULL;
6211 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6213 method = mono_object_get_virtual_method (obj, to_string);
6215 // Unbox value type if needed
6216 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6217 target = mono_object_unbox (obj);
6220 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6224 * mono_print_unhandled_exception:
6225 * @exc: The exception
6227 * Prints the unhandled exception.
6230 mono_print_unhandled_exception (MonoObject *exc)
6233 char *message = (char*)"";
6234 gboolean free_message = FALSE;
6237 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6238 message = g_strdup ("OutOfMemoryException");
6239 free_message = TRUE;
6242 if (((MonoException*)exc)->native_trace_ips) {
6243 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6244 free_message = TRUE;
6246 MonoObject *other_exc = NULL;
6247 str = mono_object_to_string (exc, &other_exc);
6249 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6250 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6252 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6253 original_backtrace, nested_backtrace);
6255 g_free (original_backtrace);
6256 g_free (nested_backtrace);
6257 free_message = TRUE;
6259 message = mono_string_to_utf8_checked (str, &error);
6260 if (!mono_error_ok (&error)) {
6261 mono_error_cleanup (&error);
6262 message = (char *) "";
6264 free_message = TRUE;
6271 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6272 * exc->vtable->klass->name, message);
6274 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6281 * mono_delegate_ctor:
6282 * @this: pointer to an uninitialized delegate object
6283 * @target: target object
6284 * @addr: pointer to native code
6287 * Initialize a delegate and sets a specific method, not the one
6288 * associated with addr. This is useful when sharing generic code.
6289 * In that case addr will most probably not be associated with the
6290 * correct instantiation of the method.
6293 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6295 MonoDelegate *delegate = (MonoDelegate *)this;
6302 delegate->method = method;
6304 class = this->vtable->klass;
6305 mono_stats.delegate_creations++;
6307 #ifndef DISABLE_REMOTING
6308 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6310 method = mono_marshal_get_remoting_invoke (method);
6311 delegate->method_ptr = mono_compile_method (method);
6312 MONO_OBJECT_SETREF (delegate, target, target);
6316 delegate->method_ptr = addr;
6317 MONO_OBJECT_SETREF (delegate, target, target);
6320 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6324 * mono_delegate_ctor:
6325 * @this: pointer to an uninitialized delegate object
6326 * @target: target object
6327 * @addr: pointer to native code
6329 * This is used to initialize a delegate.
6332 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6334 MonoDomain *domain = mono_domain_get ();
6336 MonoMethod *method = NULL;
6340 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6342 if (!ji && domain != mono_get_root_domain ())
6343 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6345 method = mono_jit_info_get_method (ji);
6346 g_assert (!method->klass->generic_container);
6349 mono_delegate_ctor_with_method (this, target, addr, method);
6353 * mono_method_call_message_new:
6354 * @method: method to encapsulate
6355 * @params: parameters to the method
6356 * @invoke: optional, delegate invoke.
6357 * @cb: async callback delegate.
6358 * @state: state passed to the async callback.
6360 * Translates arguments pointers into a MonoMethodMessage.
6363 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6364 MonoDelegate **cb, MonoObject **state)
6366 MonoDomain *domain = mono_domain_get ();
6367 MonoMethodSignature *sig = mono_method_signature (method);
6368 MonoMethodMessage *msg;
6371 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6374 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6375 count = sig->param_count - 2;
6377 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6378 count = sig->param_count;
6381 for (i = 0; i < count; i++) {
6386 if (sig->params [i]->byref)
6387 vpos = *((gpointer *)params [i]);
6391 type = sig->params [i]->type;
6392 class = mono_class_from_mono_type (sig->params [i]);
6394 if (class->valuetype)
6395 arg = mono_value_box (domain, class, vpos);
6397 arg = *((MonoObject **)vpos);
6399 mono_array_setref (msg->args, i, arg);
6402 if (cb != NULL && state != NULL) {
6403 *cb = *((MonoDelegate **)params [i]);
6405 *state = *((MonoObject **)params [i]);
6412 * mono_method_return_message_restore:
6414 * Restore results from message based processing back to arguments pointers
6417 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6419 MonoMethodSignature *sig = mono_method_signature (method);
6420 int i, j, type, size, out_len;
6422 if (out_args == NULL)
6424 out_len = mono_array_length (out_args);
6428 for (i = 0, j = 0; i < sig->param_count; i++) {
6429 MonoType *pt = sig->params [i];
6434 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6436 arg = mono_array_get (out_args, gpointer, j);
6439 g_assert (type != MONO_TYPE_VOID);
6441 if (MONO_TYPE_IS_REFERENCE (pt)) {
6442 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6445 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6446 size = mono_class_value_size (class, NULL);
6447 if (class->has_references)
6448 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6450 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6452 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6453 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6462 #ifndef DISABLE_REMOTING
6465 * mono_load_remote_field:
6466 * @this: pointer to an object
6467 * @klass: klass of the object containing @field
6468 * @field: the field to load
6469 * @res: a storage to store the result
6471 * This method is called by the runtime on attempts to load fields of
6472 * transparent proxy objects. @this points to such TP, @klass is the class of
6473 * the object containing @field. @res is a storage location which can be
6474 * used to store the result.
6476 * Returns: an address pointing to the value of field.
6479 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6481 static MonoMethod *getter = NULL;
6482 MonoDomain *domain = mono_domain_get ();
6483 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6484 MonoClass *field_class;
6485 MonoMethodMessage *msg;
6486 MonoArray *out_args;
6490 g_assert (mono_object_is_transparent_proxy (this));
6491 g_assert (res != NULL);
6493 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6494 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6499 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6503 field_class = mono_class_from_mono_type (field->type);
6505 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6506 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6507 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6509 full_name = mono_type_get_full_name (klass);
6510 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6511 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6514 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6516 if (exc) mono_raise_exception ((MonoException *)exc);
6518 if (mono_array_length (out_args) == 0)
6521 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6523 if (field_class->valuetype) {
6524 return ((char *)*res) + sizeof (MonoObject);
6530 * mono_load_remote_field_new:
6535 * Missing documentation.
6538 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6540 static MonoMethod *getter = NULL;
6541 MonoDomain *domain = mono_domain_get ();
6542 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6543 MonoClass *field_class;
6544 MonoMethodMessage *msg;
6545 MonoArray *out_args;
6546 MonoObject *exc, *res;
6549 g_assert (mono_object_is_transparent_proxy (this));
6551 field_class = mono_class_from_mono_type (field->type);
6553 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6555 if (field_class->valuetype) {
6556 res = mono_object_new (domain, field_class);
6557 val = ((gchar *) res) + sizeof (MonoObject);
6561 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6566 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6570 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6571 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6573 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6575 full_name = mono_type_get_full_name (klass);
6576 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6577 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6580 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6582 if (exc) mono_raise_exception ((MonoException *)exc);
6584 if (mono_array_length (out_args) == 0)
6587 res = mono_array_get (out_args, MonoObject *, 0);
6593 * mono_store_remote_field:
6594 * @this: pointer to an object
6595 * @klass: klass of the object containing @field
6596 * @field: the field to load
6597 * @val: the value/object to store
6599 * This method is called by the runtime on attempts to store fields of
6600 * transparent proxy objects. @this points to such TP, @klass is the class of
6601 * the object containing @field. @val is the new value to store in @field.
6604 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6606 static MonoMethod *setter = NULL;
6607 MonoDomain *domain = mono_domain_get ();
6608 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6609 MonoClass *field_class;
6610 MonoMethodMessage *msg;
6611 MonoArray *out_args;
6616 g_assert (mono_object_is_transparent_proxy (this));
6618 field_class = mono_class_from_mono_type (field->type);
6620 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6621 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6622 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6627 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6631 if (field_class->valuetype)
6632 arg = mono_value_box (domain, field_class, val);
6634 arg = *((MonoObject **)val);
6637 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6638 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6640 full_name = mono_type_get_full_name (klass);
6641 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6642 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6643 mono_array_setref (msg->args, 2, arg);
6646 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6648 if (exc) mono_raise_exception ((MonoException *)exc);
6652 * mono_store_remote_field_new:
6658 * Missing documentation
6661 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6663 static MonoMethod *setter = NULL;
6664 MonoDomain *domain = mono_domain_get ();
6665 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6666 MonoClass *field_class;
6667 MonoMethodMessage *msg;
6668 MonoArray *out_args;
6672 g_assert (mono_object_is_transparent_proxy (this));
6674 field_class = mono_class_from_mono_type (field->type);
6676 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6677 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6678 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6683 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6687 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6688 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6690 full_name = mono_type_get_full_name (klass);
6691 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6692 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6693 mono_array_setref (msg->args, 2, arg);
6696 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6698 if (exc) mono_raise_exception ((MonoException *)exc);
6703 * mono_create_ftnptr:
6705 * Given a function address, create a function descriptor for it.
6706 * This is only needed on some platforms.
6709 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6711 return callbacks.create_ftnptr (domain, addr);
6715 * mono_get_addr_from_ftnptr:
6717 * Given a pointer to a function descriptor, return the function address.
6718 * This is only needed on some platforms.
6721 mono_get_addr_from_ftnptr (gpointer descr)
6723 return callbacks.get_addr_from_ftnptr (descr);
6727 * mono_string_chars:
6730 * Returns a pointer to the UCS16 characters stored in the MonoString
6733 mono_string_chars (MonoString *s)
6739 * mono_string_length:
6742 * Returns the lenght in characters of the string
6745 mono_string_length (MonoString *s)
6751 * mono_array_length:
6752 * @array: a MonoArray*
6754 * Returns the total number of elements in the array. This works for
6755 * both vectors and multidimensional arrays.
6758 mono_array_length (MonoArray *array)
6760 return array->max_length;
6764 * mono_array_addr_with_size:
6765 * @array: a MonoArray*
6766 * @size: size of the array elements
6767 * @idx: index into the array
6769 * Returns the address of the @idx element in the array.
6772 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6774 return ((char*)(array)->vector) + size * idx;