2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/threadpool.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internal.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include "cominterop.h"
50 #define NEED_TO_ZERO_PTRFREE 1
51 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
52 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
53 #ifdef HAVE_GC_GCJ_MALLOC
54 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
62 #define GC_NO_DESCRIPTOR (NULL)
63 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
65 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
67 #define NEED_TO_ZERO_PTRFREE 1
68 #define GC_NO_DESCRIPTOR (NULL)
69 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
70 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
71 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
75 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
76 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
79 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
82 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
85 free_main_args (void);
88 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
91 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
92 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
93 static mono_mutex_t ldstr_section;
95 static gboolean profile_allocs = TRUE;
98 mono_runtime_object_init (MonoObject *this)
100 MonoMethod *method = NULL;
101 MonoClass *klass = this->vtable->klass;
103 method = mono_class_get_method_from_name (klass, ".ctor", 0);
105 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
107 if (method->klass->valuetype)
108 this = mono_object_unbox (this);
109 mono_runtime_invoke (method, this, NULL, NULL);
112 /* The pseudo algorithm for type initialization from the spec
113 Note it doesn't say anything about domains - only threads.
115 2. If the type is initialized you are done.
116 2.1. If the type is not yet initialized, try to take an
118 2.2. If successful, record this thread as responsible for
119 initializing the type and proceed to step 2.3.
120 2.2.1. If not, see whether this thread or any thread
121 waiting for this thread to complete already holds the lock.
122 2.2.2. If so, return since blocking would create a deadlock. This thread
123 will now see an incompletely initialized state for the type,
124 but no deadlock will arise.
125 2.2.3 If not, block until the type is initialized then return.
126 2.3 Initialize the parent type and then all interfaces implemented
128 2.4 Execute the type initialization code for this type.
129 2.5 Mark the type as initialized, release the initialization lock,
130 awaken any threads waiting for this type to be initialized,
137 guint32 initializing_tid;
138 guint32 waiting_count;
140 mono_mutex_t initialization_section;
141 } TypeInitializationLock;
143 /* for locking access to type_initialization_hash and blocked_thread_hash */
144 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
145 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
146 static mono_mutex_t type_initialization_section;
148 /* from vtable to lock */
149 static GHashTable *type_initialization_hash;
151 /* from thread id to thread id being waited on */
152 static GHashTable *blocked_thread_hash;
155 static MonoThread *main_thread;
157 /* Functions supplied by the runtime */
158 static MonoRuntimeCallbacks callbacks;
161 * mono_thread_set_main:
162 * @thread: thread to set as the main thread
164 * This function can be used to instruct the runtime to treat @thread
165 * as the main thread, ie, the thread that would normally execute the Main()
166 * method. This basically means that at the end of @thread, the runtime will
167 * wait for the existing foreground threads to quit and other such details.
170 mono_thread_set_main (MonoThread *thread)
172 static gboolean registered = FALSE;
175 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
179 main_thread = thread;
183 mono_thread_get_main (void)
189 mono_type_initialization_init (void)
191 mono_mutex_init_recursive (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 mono_mutex_init_recursive (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 mono_mutex_destroy (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 mono_mutex_destroy (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MonoDomain *domain = vtable->domain;
224 MonoClass *klass = vtable->klass;
228 if (!vtable->init_failed)
229 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
232 * If the initializing thread was rudely aborted, the exception is not stored
236 mono_domain_lock (domain);
237 if (domain->type_init_exception_hash)
238 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
239 mono_domain_unlock (domain);
242 if (klass->name_space && *klass->name_space)
243 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
245 full_name = g_strdup (klass->name);
246 ex = mono_get_exception_type_initialization (full_name, NULL);
253 * mono_runtime_class_init:
254 * @vtable: vtable that needs to be initialized
256 * This routine calls the class constructor for @vtable.
259 mono_runtime_class_init (MonoVTable *vtable)
261 mono_runtime_class_init_full (vtable, TRUE);
265 * mono_runtime_class_init_full:
266 * @vtable that neeeds to be initialized
267 * @raise_exception is TRUE, exceptions are raised intead of returned
271 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
274 MonoException *exc_to_throw;
275 MonoMethod *method = NULL;
281 if (vtable->initialized)
285 klass = vtable->klass;
287 if (!klass->image->checked_module_cctor) {
288 mono_image_check_for_module_cctor (klass->image);
289 if (klass->image->has_module_cctor) {
291 MonoClass *module_klass;
292 MonoVTable *module_vtable;
294 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
296 exc = mono_error_convert_to_exception (&error);
298 mono_raise_exception (exc);
302 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
305 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
310 method = mono_class_get_cctor (klass);
313 MonoDomain *domain = vtable->domain;
314 TypeInitializationLock *lock;
315 guint32 tid = GetCurrentThreadId();
316 int do_initialization = 0;
317 MonoDomain *last_domain = NULL;
319 mono_type_initialization_lock ();
320 /* double check... */
321 if (vtable->initialized) {
322 mono_type_initialization_unlock ();
325 if (vtable->init_failed) {
326 mono_type_initialization_unlock ();
328 /* The type initialization already failed once, rethrow the same exception */
330 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
331 return get_type_init_exception_for_vtable (vtable);
333 lock = g_hash_table_lookup (type_initialization_hash, vtable);
335 /* This thread will get to do the initialization */
336 if (mono_domain_get () != domain) {
337 /* Transfer into the target domain */
338 last_domain = mono_domain_get ();
339 if (!mono_domain_set (domain, FALSE)) {
340 vtable->initialized = 1;
341 mono_type_initialization_unlock ();
343 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
344 return mono_get_exception_appdomain_unloaded ();
347 lock = g_malloc (sizeof(TypeInitializationLock));
348 mono_mutex_init_recursive (&lock->initialization_section);
349 lock->initializing_tid = tid;
350 lock->waiting_count = 1;
352 /* grab the vtable lock while this thread still owns type_initialization_section */
353 mono_mutex_lock (&lock->initialization_section);
354 g_hash_table_insert (type_initialization_hash, vtable, lock);
355 do_initialization = 1;
358 TypeInitializationLock *pending_lock;
360 if (lock->initializing_tid == tid || lock->done) {
361 mono_type_initialization_unlock ();
364 /* see if the thread doing the initialization is already blocked on this thread */
365 blocked = GUINT_TO_POINTER (lock->initializing_tid);
366 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
367 if (pending_lock->initializing_tid == tid) {
368 if (!pending_lock->done) {
369 mono_type_initialization_unlock ();
372 /* the thread doing the initialization is blocked on this thread,
373 but on a lock that has already been freed. It just hasn't got
378 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
380 ++lock->waiting_count;
381 /* record the fact that we are waiting on the initializing thread */
382 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
384 mono_type_initialization_unlock ();
386 if (do_initialization) {
387 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
389 /* If the initialization failed, mark the class as unusable. */
390 /* Avoid infinite loops */
392 (klass->image == mono_defaults.corlib &&
393 !strcmp (klass->name_space, "System") &&
394 !strcmp (klass->name, "TypeInitializationException")))) {
395 vtable->init_failed = 1;
397 if (klass->name_space && *klass->name_space)
398 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
400 full_name = g_strdup (klass->name);
401 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
405 * Store the exception object so it could be thrown on subsequent
408 mono_domain_lock (domain);
409 if (!domain->type_init_exception_hash)
410 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
411 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
412 mono_domain_unlock (domain);
416 mono_domain_set (last_domain, TRUE);
418 mono_mutex_unlock (&lock->initialization_section);
420 /* this just blocks until the initializing thread is done */
421 mono_mutex_lock (&lock->initialization_section);
422 mono_mutex_unlock (&lock->initialization_section);
425 mono_type_initialization_lock ();
426 if (lock->initializing_tid != tid)
427 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
428 --lock->waiting_count;
429 if (lock->waiting_count == 0) {
430 mono_mutex_destroy (&lock->initialization_section);
431 g_hash_table_remove (type_initialization_hash, vtable);
434 mono_memory_barrier ();
435 if (!vtable->init_failed)
436 vtable->initialized = 1;
437 mono_type_initialization_unlock ();
439 if (vtable->init_failed) {
440 /* Either we were the initializing thread or we waited for the initialization */
442 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
443 return get_type_init_exception_for_vtable (vtable);
446 vtable->initialized = 1;
453 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
455 MonoVTable *vtable = (MonoVTable*)key;
457 TypeInitializationLock *lock = (TypeInitializationLock*) value;
458 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
461 * Have to set this since it cannot be set by the normal code in
462 * mono_runtime_class_init (). In this case, the exception object is not stored,
463 * and get_type_init_exception_for_class () needs to be aware of this.
465 vtable->init_failed = 1;
466 mono_mutex_unlock (&lock->initialization_section);
467 --lock->waiting_count;
468 if (lock->waiting_count == 0) {
469 mono_mutex_destroy (&lock->initialization_section);
478 mono_release_type_locks (MonoInternalThread *thread)
480 mono_type_initialization_lock ();
481 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
482 mono_type_initialization_unlock ();
486 default_trampoline (MonoMethod *method)
492 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
494 g_assert_not_reached ();
499 #ifndef DISABLE_REMOTING
502 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
504 g_error ("remoting not installed");
508 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
512 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
514 g_assert_not_reached ();
518 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
519 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
520 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
521 static MonoImtThunkBuilder imt_thunk_builder = NULL;
522 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
523 #if (MONO_IMT_SIZE > 32)
524 #error "MONO_IMT_SIZE cannot be larger than 32"
528 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
530 memcpy (&callbacks, cbs, sizeof (*cbs));
533 MonoRuntimeCallbacks*
534 mono_get_runtime_callbacks (void)
540 mono_install_trampoline (MonoTrampoline func)
542 arch_create_jit_trampoline = func? func: default_trampoline;
546 mono_install_jump_trampoline (MonoJumpTrampoline func)
548 arch_create_jump_trampoline = func? func: default_jump_trampoline;
551 #ifndef DISABLE_REMOTING
553 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
555 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
560 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
562 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
566 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
567 imt_thunk_builder = func;
570 static MonoCompileFunc default_mono_compile_method = NULL;
573 * mono_install_compile_method:
574 * @func: function to install
576 * This is a VM internal routine
579 mono_install_compile_method (MonoCompileFunc func)
581 default_mono_compile_method = func;
585 * mono_compile_method:
586 * @method: The method to compile.
588 * This JIT-compiles the method, and returns the pointer to the native code
592 mono_compile_method (MonoMethod *method)
594 if (!default_mono_compile_method) {
595 g_error ("compile method called on uninitialized runtime");
598 return default_mono_compile_method (method);
602 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
604 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
608 mono_runtime_create_delegate_trampoline (MonoClass *klass)
610 return arch_create_delegate_trampoline (mono_domain_get (), klass);
613 static MonoFreeMethodFunc default_mono_free_method = NULL;
616 * mono_install_free_method:
617 * @func: pointer to the MonoFreeMethodFunc used to release a method
619 * This is an internal VM routine, it is used for the engines to
620 * register a handler to release the resources associated with a method.
622 * Methods are freed when no more references to the delegate that holds
626 mono_install_free_method (MonoFreeMethodFunc func)
628 default_mono_free_method = func;
632 * mono_runtime_free_method:
633 * @domain; domain where the method is hosted
634 * @method: method to release
636 * This routine is invoked to free the resources associated with
637 * a method that has been JIT compiled. This is used to discard
638 * methods that were used only temporarily (for example, used in marshalling)
642 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
644 if (default_mono_free_method != NULL)
645 default_mono_free_method (domain, method);
647 mono_method_clear_object (domain, method);
649 mono_free_method (method);
653 * The vtables in the root appdomain are assumed to be reachable by other
654 * roots, and we don't use typed allocation in the other domains.
657 /* The sync block is no longer a GC pointer */
658 #define GC_HEADER_BITMAP (0)
660 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
663 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
665 MonoClassField *field;
671 max_size = mono_class_data_size (class) / sizeof (gpointer);
673 max_size = class->instance_size / sizeof (gpointer);
674 if (max_size > size) {
675 g_assert (offset <= 0);
676 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
681 /*An Ephemeron cannot be marked by sgen*/
682 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
684 memset (bitmap, 0, size / 8);
689 for (p = class; p != NULL; p = p->parent) {
690 gpointer iter = NULL;
691 while ((field = mono_class_get_fields (p, &iter))) {
695 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
697 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
700 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
703 /* FIXME: should not happen, flag as type load error */
704 if (field->type->byref)
707 if (static_fields && field->offset == -1)
711 pos = field->offset / sizeof (gpointer);
714 type = mono_type_get_underlying_type (field->type);
715 switch (type->type) {
718 case MONO_TYPE_FNPTR:
720 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
725 if (class->image != mono_defaults.corlib)
728 case MONO_TYPE_STRING:
729 case MONO_TYPE_SZARRAY:
730 case MONO_TYPE_CLASS:
731 case MONO_TYPE_OBJECT:
732 case MONO_TYPE_ARRAY:
733 g_assert ((field->offset % sizeof(gpointer)) == 0);
735 g_assert (pos < size || pos <= max_size);
736 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
737 *max_set = MAX (*max_set, pos);
739 case MONO_TYPE_GENERICINST:
740 if (!mono_type_generic_inst_is_valuetype (type)) {
741 g_assert ((field->offset % sizeof(gpointer)) == 0);
743 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
744 *max_set = MAX (*max_set, pos);
749 case MONO_TYPE_VALUETYPE: {
750 MonoClass *fclass = mono_class_from_mono_type (field->type);
751 if (fclass->has_references) {
752 /* remove the object header */
753 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
767 case MONO_TYPE_BOOLEAN:
771 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
782 * mono_class_compute_bitmap:
784 * Mono internal function to compute a bitmap of reference fields in a class.
787 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
789 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
794 * similar to the above, but sets the bits in the bitmap for any non-ref field
795 * and ignores static fields
798 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
800 MonoClassField *field;
805 max_size = class->instance_size / sizeof (gpointer);
806 if (max_size >= size) {
807 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
810 for (p = class; p != NULL; p = p->parent) {
811 gpointer iter = NULL;
812 while ((field = mono_class_get_fields (p, &iter))) {
815 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
817 /* FIXME: should not happen, flag as type load error */
818 if (field->type->byref)
821 pos = field->offset / sizeof (gpointer);
824 type = mono_type_get_underlying_type (field->type);
825 switch (type->type) {
826 #if SIZEOF_VOID_P == 8
830 case MONO_TYPE_FNPTR:
835 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
836 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
837 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
840 #if SIZEOF_VOID_P == 4
844 case MONO_TYPE_FNPTR:
849 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
850 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
851 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
857 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
858 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
859 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
862 case MONO_TYPE_BOOLEAN:
865 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
867 case MONO_TYPE_STRING:
868 case MONO_TYPE_SZARRAY:
869 case MONO_TYPE_CLASS:
870 case MONO_TYPE_OBJECT:
871 case MONO_TYPE_ARRAY:
873 case MONO_TYPE_GENERICINST:
874 if (!mono_type_generic_inst_is_valuetype (type)) {
879 case MONO_TYPE_VALUETYPE: {
880 MonoClass *fclass = mono_class_from_mono_type (field->type);
881 /* remove the object header */
882 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
886 g_assert_not_reached ();
895 * mono_class_insecure_overlapping:
896 * check if a class with explicit layout has references and non-references
897 * fields overlapping.
899 * Returns: TRUE if it is insecure to load the type.
902 mono_class_insecure_overlapping (MonoClass *klass)
906 gsize default_bitmap [4] = {0};
908 gsize default_nrbitmap [4] = {0};
909 int i, insecure = FALSE;
912 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
913 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
915 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
916 int idx = i % (sizeof (bitmap [0]) * 8);
917 if (bitmap [idx] & nrbitmap [idx]) {
922 if (bitmap != default_bitmap)
924 if (nrbitmap != default_nrbitmap)
927 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
935 mono_string_alloc (int length)
937 return mono_string_new_size (mono_domain_get (), length);
941 mono_class_compute_gc_descriptor (MonoClass *class)
945 gsize default_bitmap [4] = {0};
946 static gboolean gcj_inited = FALSE;
951 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
952 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
953 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
954 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
956 #ifdef HAVE_GC_GCJ_MALLOC
958 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
962 #ifdef GC_REDIRECT_TO_LOCAL
963 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
964 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
966 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
967 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
972 mono_loader_unlock ();
976 mono_class_init (class);
978 if (class->gc_descr_inited)
981 class->gc_descr_inited = TRUE;
982 class->gc_descr = GC_NO_DESCRIPTOR;
984 bitmap = default_bitmap;
985 if (class == mono_defaults.string_class) {
986 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
987 } else if (class->rank) {
988 mono_class_compute_gc_descriptor (class->element_class);
989 if (!class->element_class->valuetype) {
991 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
992 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
993 class->name_space, class->name);*/
995 /* remove the object header */
996 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
997 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
998 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
999 class->name_space, class->name);*/
1000 if (bitmap != default_bitmap)
1004 /*static int count = 0;
1007 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1008 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1010 if (class->gc_descr == GC_NO_DESCRIPTOR)
1011 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1013 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1014 if (bitmap != default_bitmap)
1020 * field_is_special_static:
1021 * @fklass: The MonoClass to look up.
1022 * @field: The MonoClassField describing the field.
1024 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1025 * SPECIAL_STATIC_NONE otherwise.
1028 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1030 MonoCustomAttrInfo *ainfo;
1032 ainfo = mono_custom_attrs_from_field (fklass, field);
1035 for (i = 0; i < ainfo->num_attrs; ++i) {
1036 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1037 if (klass->image == mono_defaults.corlib) {
1038 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1039 mono_custom_attrs_free (ainfo);
1040 return SPECIAL_STATIC_THREAD;
1042 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1043 mono_custom_attrs_free (ainfo);
1044 return SPECIAL_STATIC_CONTEXT;
1048 mono_custom_attrs_free (ainfo);
1049 return SPECIAL_STATIC_NONE;
1052 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1053 #define mix(a,b,c) { \
1054 a -= c; a ^= rot(c, 4); c += b; \
1055 b -= a; b ^= rot(a, 6); a += c; \
1056 c -= b; c ^= rot(b, 8); b += a; \
1057 a -= c; a ^= rot(c,16); c += b; \
1058 b -= a; b ^= rot(a,19); a += c; \
1059 c -= b; c ^= rot(b, 4); b += a; \
1061 #define final(a,b,c) { \
1062 c ^= b; c -= rot(b,14); \
1063 a ^= c; a -= rot(c,11); \
1064 b ^= a; b -= rot(a,25); \
1065 c ^= b; c -= rot(b,16); \
1066 a ^= c; a -= rot(c,4); \
1067 b ^= a; b -= rot(a,14); \
1068 c ^= b; c -= rot(b,24); \
1072 * mono_method_get_imt_slot:
1074 * The IMT slot is embedded into AOTed code, so this must return the same value
1075 * for the same method across all executions. This means:
1076 * - pointers shouldn't be used as hash values.
1077 * - mono_metadata_str_hash () should be used for hashing strings.
1080 mono_method_get_imt_slot (MonoMethod *method)
1082 MonoMethodSignature *sig;
1084 guint32 *hashes_start, *hashes;
1088 /* This can be used to stress tests the collision code */
1092 * We do this to simplify generic sharing. It will hurt
1093 * performance in cases where a class implements two different
1094 * instantiations of the same generic interface.
1095 * The code in build_imt_slots () depends on this.
1097 if (method->is_inflated)
1098 method = ((MonoMethodInflated*)method)->declaring;
1100 sig = mono_method_signature (method);
1101 hashes_count = sig->param_count + 4;
1102 hashes_start = malloc (hashes_count * sizeof (guint32));
1103 hashes = hashes_start;
1105 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1106 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1107 method->klass->name_space, method->klass->name, method->name);
1110 /* Initialize hashes */
1111 hashes [0] = mono_metadata_str_hash (method->klass->name);
1112 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1113 hashes [2] = mono_metadata_str_hash (method->name);
1114 hashes [3] = mono_metadata_type_hash (sig->ret);
1115 for (i = 0; i < sig->param_count; i++) {
1116 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1119 /* Setup internal state */
1120 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1122 /* Handle most of the hashes */
1123 while (hashes_count > 3) {
1132 /* Handle the last 3 hashes (all the case statements fall through) */
1133 switch (hashes_count) {
1134 case 3 : c += hashes [2];
1135 case 2 : b += hashes [1];
1136 case 1 : a += hashes [0];
1138 case 0: /* nothing left to add */
1142 free (hashes_start);
1143 /* Report the result */
1144 return c % MONO_IMT_SIZE;
1153 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1154 guint32 imt_slot = mono_method_get_imt_slot (method);
1155 MonoImtBuilderEntry *entry;
1157 if (slot_num >= 0 && imt_slot != slot_num) {
1158 /* we build just a single imt slot and this is not it */
1162 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1163 entry->key = method;
1164 entry->value.vtable_slot = vtable_slot;
1165 entry->next = imt_builder [imt_slot];
1166 if (imt_builder [imt_slot] != NULL) {
1167 entry->children = imt_builder [imt_slot]->children + 1;
1168 if (entry->children == 1) {
1169 mono_stats.imt_slots_with_collisions++;
1170 *imt_collisions_bitmap |= (1 << imt_slot);
1173 entry->children = 0;
1174 mono_stats.imt_used_slots++;
1176 imt_builder [imt_slot] = entry;
1179 char *method_name = mono_method_full_name (method, TRUE);
1180 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1181 method, method_name, imt_slot, vtable_slot, entry->children);
1182 g_free (method_name);
1189 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1191 MonoMethod *method = e->key;
1192 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1196 method->klass->name_space,
1197 method->klass->name,
1200 printf (" * %s: NULL\n", message);
1206 compare_imt_builder_entries (const void *p1, const void *p2) {
1207 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1208 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1210 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1214 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1216 int count = end - start;
1217 int chunk_start = out_array->len;
1220 for (i = start; i < end; ++i) {
1221 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1222 item->key = sorted_array [i]->key;
1223 item->value = sorted_array [i]->value;
1224 item->has_target_code = sorted_array [i]->has_target_code;
1225 item->is_equals = TRUE;
1227 item->check_target_idx = out_array->len + 1;
1229 item->check_target_idx = 0;
1230 g_ptr_array_add (out_array, item);
1233 int middle = start + count / 2;
1234 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1236 item->key = sorted_array [middle]->key;
1237 item->is_equals = FALSE;
1238 g_ptr_array_add (out_array, item);
1239 imt_emit_ir (sorted_array, start, middle, out_array);
1240 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1246 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1247 int number_of_entries = entries->children + 1;
1248 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1249 GPtrArray *result = g_ptr_array_new ();
1250 MonoImtBuilderEntry *current_entry;
1253 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1254 sorted_array [i] = current_entry;
1256 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1258 /*for (i = 0; i < number_of_entries; i++) {
1259 print_imt_entry (" sorted array:", sorted_array [i], i);
1262 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1264 free (sorted_array);
1269 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1271 if (imt_builder_entry != NULL) {
1272 if (imt_builder_entry->children == 0 && !fail_tramp) {
1273 /* No collision, return the vtable slot contents */
1274 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1276 /* Collision, build the thunk */
1277 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1280 result = imt_thunk_builder (vtable, domain,
1281 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1282 for (i = 0; i < imt_ir->len; ++i)
1283 g_free (g_ptr_array_index (imt_ir, i));
1284 g_ptr_array_free (imt_ir, TRUE);
1296 static MonoImtBuilderEntry*
1297 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1300 * LOCKING: requires the loader and domain locks.
1304 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1308 guint32 imt_collisions_bitmap = 0;
1309 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1310 int method_count = 0;
1311 gboolean record_method_count_for_max_collisions = FALSE;
1312 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1315 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1317 for (i = 0; i < klass->interface_offsets_count; ++i) {
1318 MonoClass *iface = klass->interfaces_packed [i];
1319 int interface_offset = klass->interface_offsets_packed [i];
1320 int method_slot_in_interface, vt_slot;
1322 if (mono_class_has_variant_generic_params (iface))
1323 has_variant_iface = TRUE;
1325 mono_class_setup_methods (iface);
1326 vt_slot = interface_offset;
1327 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1330 if (slot_num >= 0 && iface->is_inflated) {
1332 * The imt slot of the method is the same as for its declaring method,
1333 * see the comment in mono_method_get_imt_slot (), so we can
1334 * avoid inflating methods which will be discarded by
1335 * add_imt_builder_entry anyway.
1337 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1338 if (mono_method_get_imt_slot (method) != slot_num) {
1343 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1344 if (method->is_generic) {
1345 has_generic_virtual = TRUE;
1350 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1351 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1356 if (extra_interfaces) {
1357 int interface_offset = klass->vtable_size;
1359 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1360 MonoClass* iface = list_item->data;
1361 int method_slot_in_interface;
1362 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1363 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1365 if (method->is_generic)
1366 has_generic_virtual = TRUE;
1367 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1369 interface_offset += iface->method.count;
1372 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1373 /* overwrite the imt slot only if we're building all the entries or if
1374 * we're building this specific one
1376 if (slot_num < 0 || i == slot_num) {
1377 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1380 if (imt_builder [i]) {
1381 MonoImtBuilderEntry *entry;
1383 /* Link entries with imt_builder [i] */
1384 for (entry = entries; entry->next; entry = entry->next) {
1386 MonoMethod *method = (MonoMethod*)entry->key;
1387 char *method_name = mono_method_full_name (method, TRUE);
1388 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1389 g_free (method_name);
1392 entry->next = imt_builder [i];
1393 entries->children += imt_builder [i]->children + 1;
1395 imt_builder [i] = entries;
1398 if (has_generic_virtual || has_variant_iface) {
1400 * There might be collisions later when the the thunk is expanded.
1402 imt_collisions_bitmap |= (1 << i);
1405 * The IMT thunk might be called with an instance of one of the
1406 * generic virtual methods, so has to fallback to the IMT trampoline.
1408 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1410 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1413 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1417 if (imt_builder [i] != NULL) {
1418 int methods_in_slot = imt_builder [i]->children + 1;
1419 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1420 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1421 record_method_count_for_max_collisions = TRUE;
1423 method_count += methods_in_slot;
1427 mono_stats.imt_number_of_methods += method_count;
1428 if (record_method_count_for_max_collisions) {
1429 mono_stats.imt_method_count_when_max_collisions = method_count;
1432 for (i = 0; i < MONO_IMT_SIZE; i++) {
1433 MonoImtBuilderEntry* entry = imt_builder [i];
1434 while (entry != NULL) {
1435 MonoImtBuilderEntry* next = entry->next;
1441 /* we OR the bitmap since we may build just a single imt slot at a time */
1442 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1446 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1447 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1451 * mono_vtable_build_imt_slot:
1452 * @vtable: virtual object table struct
1453 * @imt_slot: slot in the IMT table
1455 * Fill the given @imt_slot in the IMT table of @vtable with
1456 * a trampoline or a thunk for the case of collisions.
1457 * This is part of the internal mono API.
1459 * LOCKING: Take the domain lock.
1462 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1464 gpointer *imt = (gpointer*)vtable;
1465 imt -= MONO_IMT_SIZE;
1466 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1468 /* no support for extra interfaces: the proxy objects will need
1469 * to build the complete IMT
1470 * Update and heck needs to ahppen inside the proper domain lock, as all
1471 * the changes made to a MonoVTable.
1473 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1474 mono_domain_lock (vtable->domain);
1475 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1476 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1477 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1478 mono_domain_unlock (vtable->domain);
1479 mono_loader_unlock ();
1484 * The first two free list entries both belong to the wait list: The
1485 * first entry is the pointer to the head of the list and the second
1486 * entry points to the last element. That way appending and removing
1487 * the first element are both O(1) operations.
1489 #ifdef MONO_SMALL_CONFIG
1490 #define NUM_FREE_LISTS 6
1492 #define NUM_FREE_LISTS 12
1494 #define FIRST_FREE_LIST_SIZE 64
1495 #define MAX_WAIT_LENGTH 50
1496 #define THUNK_THRESHOLD 10
1499 * LOCKING: The domain lock must be held.
1502 init_thunk_free_lists (MonoDomain *domain)
1504 if (domain->thunk_free_lists)
1506 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1510 list_index_for_size (int item_size)
1513 int size = FIRST_FREE_LIST_SIZE;
1515 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1524 * mono_method_alloc_generic_virtual_thunk:
1526 * @size: size in bytes
1528 * Allocs size bytes to be used for the code of a generic virtual
1529 * thunk. It's either allocated from the domain's code manager or
1530 * reused from a previously invalidated piece.
1532 * LOCKING: The domain lock must be held.
1535 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1537 static gboolean inited = FALSE;
1538 static int generic_virtual_thunks_size = 0;
1542 MonoThunkFreeList **l;
1544 init_thunk_free_lists (domain);
1546 size += sizeof (guint32);
1547 if (size < sizeof (MonoThunkFreeList))
1548 size = sizeof (MonoThunkFreeList);
1550 i = list_index_for_size (size);
1551 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1552 if ((*l)->size >= size) {
1553 MonoThunkFreeList *item = *l;
1555 return ((guint32*)item) + 1;
1559 /* no suitable item found - search lists of larger sizes */
1560 while (++i < NUM_FREE_LISTS) {
1561 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1564 g_assert (item->size > size);
1565 domain->thunk_free_lists [i] = item->next;
1566 return ((guint32*)item) + 1;
1569 /* still nothing found - allocate it */
1571 mono_counters_register ("Generic virtual thunk bytes",
1572 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1575 generic_virtual_thunks_size += size;
1577 p = mono_domain_code_reserve (domain, size);
1580 mono_domain_lock (domain);
1581 if (!domain->generic_virtual_thunks)
1582 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1583 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1584 mono_domain_unlock (domain);
1590 * LOCKING: The domain lock must be held.
1593 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1596 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1597 gboolean found = FALSE;
1599 mono_domain_lock (domain);
1600 if (!domain->generic_virtual_thunks)
1601 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1602 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1604 mono_domain_unlock (domain);
1607 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1609 init_thunk_free_lists (domain);
1611 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1612 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1613 int length = item->length;
1616 /* unlink the first item from the wait list */
1617 domain->thunk_free_lists [0] = item->next;
1618 domain->thunk_free_lists [0]->length = length - 1;
1620 i = list_index_for_size (item->size);
1622 /* put it in the free list */
1623 item->next = domain->thunk_free_lists [i];
1624 domain->thunk_free_lists [i] = item;
1628 if (domain->thunk_free_lists [1]) {
1629 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1630 domain->thunk_free_lists [0]->length++;
1632 g_assert (!domain->thunk_free_lists [0]);
1634 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1635 domain->thunk_free_lists [0]->length = 1;
1639 typedef struct _GenericVirtualCase {
1643 struct _GenericVirtualCase *next;
1644 } GenericVirtualCase;
1647 * get_generic_virtual_entries:
1649 * Return IMT entries for the generic virtual method instances and
1650 * variant interface methods for vtable slot
1653 static MonoImtBuilderEntry*
1654 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1656 GenericVirtualCase *list;
1657 MonoImtBuilderEntry *entries;
1659 mono_domain_lock (domain);
1660 if (!domain->generic_virtual_cases)
1661 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1663 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1666 for (; list; list = list->next) {
1667 MonoImtBuilderEntry *entry;
1669 if (list->count < THUNK_THRESHOLD)
1672 entry = g_new0 (MonoImtBuilderEntry, 1);
1673 entry->key = list->method;
1674 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1675 entry->has_target_code = 1;
1677 entry->children = entries->children + 1;
1678 entry->next = entries;
1682 mono_domain_unlock (domain);
1684 /* FIXME: Leaking memory ? */
1689 * mono_method_add_generic_virtual_invocation:
1691 * @vtable_slot: pointer to the vtable slot
1692 * @method: the inflated generic virtual method
1693 * @code: the method's code
1695 * Registers a call via unmanaged code to a generic virtual method
1696 * instantiation or variant interface method. If the number of calls reaches a threshold
1697 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1698 * virtual method thunk.
1701 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1702 gpointer *vtable_slot,
1703 MonoMethod *method, gpointer code)
1705 static gboolean inited = FALSE;
1706 static int num_added = 0;
1708 GenericVirtualCase *gvc, *list;
1709 MonoImtBuilderEntry *entries;
1713 mono_domain_lock (domain);
1714 if (!domain->generic_virtual_cases)
1715 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1717 /* Check whether the case was already added */
1718 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1721 if (gvc->method == method)
1726 /* If not found, make a new one */
1728 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1729 gvc->method = method;
1732 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1734 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1737 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1743 if (++gvc->count == THUNK_THRESHOLD) {
1744 gpointer *old_thunk = *vtable_slot;
1745 gpointer vtable_trampoline = NULL;
1746 gpointer imt_trampoline = NULL;
1748 if ((gpointer)vtable_slot < (gpointer)vtable) {
1749 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1750 int imt_slot = MONO_IMT_SIZE + displacement;
1752 /* Force the rebuild of the thunk at the next call */
1753 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1754 *vtable_slot = imt_trampoline;
1756 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1758 entries = get_generic_virtual_entries (domain, vtable_slot);
1760 sorted = imt_sort_slot_entries (entries);
1762 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1766 MonoImtBuilderEntry *next = entries->next;
1771 for (i = 0; i < sorted->len; ++i)
1772 g_free (g_ptr_array_index (sorted, i));
1773 g_ptr_array_free (sorted, TRUE);
1776 #ifndef __native_client__
1777 /* We don't re-use any thunks as there is a lot of overhead */
1778 /* to deleting and re-using code in Native Client. */
1779 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1780 invalidate_generic_virtual_thunk (domain, old_thunk);
1784 mono_domain_unlock (domain);
1787 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1790 * mono_class_vtable:
1791 * @domain: the application domain
1792 * @class: the class to initialize
1794 * VTables are domain specific because we create domain specific code, and
1795 * they contain the domain specific static class data.
1796 * On failure, NULL is returned, and class->exception_type is set.
1799 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1801 return mono_class_vtable_full (domain, class, FALSE);
1805 * mono_class_vtable_full:
1806 * @domain: the application domain
1807 * @class: the class to initialize
1808 * @raise_on_error if an exception should be raised on failure or not
1810 * VTables are domain specific because we create domain specific code, and
1811 * they contain the domain specific static class data.
1814 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1816 MonoClassRuntimeInfo *runtime_info;
1820 if (class->exception_type) {
1822 mono_raise_exception (mono_class_get_exception_for_failure (class));
1826 /* this check can be inlined in jitted code, too */
1827 runtime_info = class->runtime_info;
1828 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1829 return runtime_info->domain_vtables [domain->domain_id];
1830 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1834 * mono_class_try_get_vtable:
1835 * @domain: the application domain
1836 * @class: the class to initialize
1838 * This function tries to get the associated vtable from @class if
1839 * it was already created.
1842 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1844 MonoClassRuntimeInfo *runtime_info;
1848 runtime_info = class->runtime_info;
1849 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1850 return runtime_info->domain_vtables [domain->domain_id];
1855 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1858 MonoClassRuntimeInfo *runtime_info, *old_info;
1859 MonoClassField *field;
1861 int i, vtable_slots;
1862 int imt_table_bytes = 0;
1865 guint32 vtable_size, class_size;
1868 gpointer *interface_offsets;
1870 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1871 mono_domain_lock (domain);
1872 runtime_info = class->runtime_info;
1873 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1874 mono_domain_unlock (domain);
1875 mono_loader_unlock ();
1876 return runtime_info->domain_vtables [domain->domain_id];
1878 if (!class->inited || class->exception_type) {
1879 if (!mono_class_init (class) || class->exception_type) {
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1883 mono_raise_exception (mono_class_get_exception_for_failure (class));
1888 /* Array types require that their element type be valid*/
1889 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1890 MonoClass *element_class = class->element_class;
1891 if (!element_class->inited)
1892 mono_class_init (element_class);
1894 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1895 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1896 mono_class_setup_vtable (element_class);
1898 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1899 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1900 if (class->exception_type == MONO_EXCEPTION_NONE)
1901 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1902 mono_domain_unlock (domain);
1903 mono_loader_unlock ();
1905 mono_raise_exception (mono_class_get_exception_for_failure (class));
1911 * For some classes, mono_class_init () already computed class->vtable_size, and
1912 * that is all that is needed because of the vtable trampolines.
1914 if (!class->vtable_size)
1915 mono_class_setup_vtable (class);
1917 if (class->generic_class && !class->vtable)
1918 mono_class_check_vtable_constraints (class, NULL);
1920 /* Initialize klass->has_finalize */
1921 mono_class_has_finalizer (class);
1923 if (class->exception_type) {
1924 mono_domain_unlock (domain);
1925 mono_loader_unlock ();
1927 mono_raise_exception (mono_class_get_exception_for_failure (class));
1931 vtable_slots = class->vtable_size;
1932 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1933 class_size = mono_class_data_size (class);
1938 vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1939 if (class->interface_offsets_count) {
1940 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1941 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1942 mono_stats.imt_number_of_tables++;
1943 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1946 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1947 MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1951 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1952 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1953 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1955 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1956 g_assert ((imt_table_bytes & 7) == 4);
1963 mono_stats.used_class_count++;
1964 mono_stats.class_vtable_size += vtable_size;
1966 interface_offsets = (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1968 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1969 g_assert (!((gsize)vt & 7));
1972 vt->rank = class->rank;
1973 vt->domain = domain;
1975 mono_class_compute_gc_descriptor (class);
1977 * We can't use typed allocation in the non-root domains, since the
1978 * collector needs the GC descriptor stored in the vtable even after
1979 * the mempool containing the vtable is destroyed when the domain is
1980 * unloaded. An alternative might be to allocate vtables in the GC
1981 * heap, but this does not seem to work (it leads to crashes inside
1982 * libgc). If that approach is tried, two gc descriptors need to be
1983 * allocated for each class: one for the root domain, and one for all
1984 * other domains. The second descriptor should contain a bit for the
1985 * vtable field in MonoObject, since we can no longer assume the
1986 * vtable is reachable by other roots after the appdomain is unloaded.
1988 #ifdef HAVE_BOEHM_GC
1989 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1990 vt->gc_descr = GC_NO_DESCRIPTOR;
1993 vt->gc_descr = class->gc_descr;
1995 gc_bits = mono_gc_get_vtable_bits (class);
1996 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1998 vt->gc_bits = gc_bits;
2001 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2002 if (class->has_static_refs) {
2003 gpointer statics_gc_descr;
2005 gsize default_bitmap [4] = {0};
2008 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2009 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2010 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2011 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2012 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2013 if (bitmap != default_bitmap)
2016 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2018 vt->has_static_fields = TRUE;
2019 mono_stats.class_static_data_size += class_size;
2024 while ((field = mono_class_get_fields (class, &iter))) {
2025 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2027 if (mono_field_is_deleted (field))
2029 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2030 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2031 if (special_static != SPECIAL_STATIC_NONE) {
2032 guint32 size, offset;
2034 gsize default_bitmap [4] = {0};
2039 if (mono_type_is_reference (field->type)) {
2040 default_bitmap [0] = 1;
2042 bitmap = default_bitmap;
2043 } else if (mono_type_is_struct (field->type)) {
2044 fclass = mono_class_from_mono_type (field->type);
2045 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2046 numbits = max_set + 1;
2048 default_bitmap [0] = 0;
2050 bitmap = default_bitmap;
2052 size = mono_type_size (field->type, &align);
2053 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2054 if (!domain->special_static_fields)
2055 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2056 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2057 if (bitmap != default_bitmap)
2060 * This marks the field as special static to speed up the
2061 * checks in mono_field_static_get/set_value ().
2067 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2068 MonoClass *fklass = mono_class_from_mono_type (field->type);
2069 const char *data = mono_field_get_data (field);
2071 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2072 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2073 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2076 if (fklass->valuetype) {
2077 memcpy (t, data, mono_class_value_size (fklass, NULL));
2079 /* it's a pointer type: add check */
2080 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2087 vt->max_interface_id = class->max_interface_id;
2088 vt->interface_bitmap = class->interface_bitmap;
2090 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2091 // class->name, class->interface_offsets_count);
2093 if (! ARCH_USE_IMT) {
2094 /* initialize interface offsets */
2095 for (i = 0; i < class->interface_offsets_count; ++i) {
2096 int interface_id = class->interfaces_packed [i]->interface_id;
2097 int slot = class->interface_offsets_packed [i];
2098 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2102 /* Initialize vtable */
2103 if (callbacks.get_vtable_trampoline) {
2104 // This also covers the AOT case
2105 for (i = 0; i < class->vtable_size; ++i) {
2106 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2109 mono_class_setup_vtable (class);
2111 for (i = 0; i < class->vtable_size; ++i) {
2114 if ((cm = class->vtable [i]))
2115 vt->vtable [i] = arch_create_jit_trampoline (cm);
2119 if (ARCH_USE_IMT && imt_table_bytes) {
2120 /* Now that the vtable is full, we can actually fill up the IMT */
2121 if (callbacks.get_imt_trampoline) {
2122 /* lazy construction of the IMT entries enabled */
2123 for (i = 0; i < MONO_IMT_SIZE; ++i)
2124 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2126 build_imt (class, vt, domain, interface_offsets, NULL);
2131 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2132 * re-acquire them and check if another thread has created the vtable in the meantime.
2134 /* Special case System.MonoType to avoid infinite recursion */
2135 if (class != mono_defaults.monotype_class) {
2136 /*FIXME check for OOM*/
2137 vt->type = mono_type_get_object (domain, &class->byval_arg);
2138 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2139 /* This is unregistered in
2140 unregister_vtable_reflection_type() in
2142 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2145 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2147 /* class_vtable_array keeps an array of created vtables
2149 g_ptr_array_add (domain->class_vtable_array, vt);
2150 /* class->runtime_info is protected by the loader lock, both when
2151 * it it enlarged and when it is stored info.
2155 * Store the vtable in class->runtime_info.
2156 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2158 mono_memory_barrier ();
2160 old_info = class->runtime_info;
2161 if (old_info && old_info->max_domain >= domain->domain_id) {
2162 /* someone already created a large enough runtime info */
2163 old_info->domain_vtables [domain->domain_id] = vt;
2165 int new_size = domain->domain_id;
2167 new_size = MAX (new_size, old_info->max_domain);
2169 /* make the new size a power of two */
2171 while (new_size > i)
2174 /* this is a bounded memory retention issue: may want to
2175 * handle it differently when we'll have a rcu-like system.
2177 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2178 runtime_info->max_domain = new_size - 1;
2179 /* copy the stuff from the older info */
2181 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2183 runtime_info->domain_vtables [domain->domain_id] = vt;
2185 mono_memory_barrier ();
2186 class->runtime_info = runtime_info;
2189 if (class == mono_defaults.monotype_class) {
2190 /*FIXME check for OOM*/
2191 vt->type = mono_type_get_object (domain, &class->byval_arg);
2192 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2193 /* This is unregistered in
2194 unregister_vtable_reflection_type() in
2196 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2199 mono_domain_unlock (domain);
2200 mono_loader_unlock ();
2202 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2203 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2204 mono_raise_exception (mono_class_get_exception_for_failure (class));
2206 /* make sure the parent is initialized */
2207 /*FIXME shouldn't this fail the current type?*/
2209 mono_class_vtable_full (domain, class->parent, raise_on_error);
2214 #ifndef DISABLE_REMOTING
2216 * mono_class_proxy_vtable:
2217 * @domain: the application domain
2218 * @remove_class: the remote class
2220 * Creates a vtable for transparent proxies. It is basically
2221 * a copy of the real vtable of the class wrapped in @remote_class,
2222 * but all function pointers invoke the remoting functions, and
2223 * vtable->klass points to the transparent proxy class, and not to @class.
2226 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2229 MonoVTable *vt, *pvt;
2230 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2232 GSList *extra_interfaces = NULL;
2233 MonoClass *class = remote_class->proxy_class;
2234 gpointer *interface_offsets;
2238 #ifdef COMPRESSED_INTERFACE_BITMAP
2242 vt = mono_class_vtable (domain, class);
2243 g_assert (vt); /*FIXME property handle failure*/
2244 max_interface_id = vt->max_interface_id;
2246 /* Calculate vtable space for extra interfaces */
2247 for (j = 0; j < remote_class->interface_count; j++) {
2248 MonoClass* iclass = remote_class->interfaces[j];
2252 /*FIXME test for interfaces with variant generic arguments*/
2253 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2254 continue; /* interface implemented by the class */
2255 if (g_slist_find (extra_interfaces, iclass))
2258 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2260 method_count = mono_class_num_methods (iclass);
2262 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2263 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2265 for (i = 0; i < ifaces->len; ++i) {
2266 MonoClass *ic = g_ptr_array_index (ifaces, i);
2267 /*FIXME test for interfaces with variant generic arguments*/
2268 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2269 continue; /* interface implemented by the class */
2270 if (g_slist_find (extra_interfaces, ic))
2272 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2273 method_count += mono_class_num_methods (ic);
2275 g_ptr_array_free (ifaces, TRUE);
2278 extra_interface_vtsize += method_count * sizeof (gpointer);
2279 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2283 mono_stats.imt_number_of_tables++;
2284 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2285 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2286 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2288 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2289 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2292 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2294 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2296 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2298 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2299 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2301 pvt->klass = mono_defaults.transparent_proxy_class;
2302 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2303 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2305 /* initialize vtable */
2306 mono_class_setup_vtable (class);
2307 for (i = 0; i < class->vtable_size; ++i) {
2310 if ((cm = class->vtable [i]))
2311 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2313 pvt->vtable [i] = NULL;
2316 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2317 /* create trampolines for abstract methods */
2318 for (k = class; k; k = k->parent) {
2320 gpointer iter = NULL;
2321 while ((m = mono_class_get_methods (k, &iter)))
2322 if (!pvt->vtable [m->slot])
2323 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2327 pvt->max_interface_id = max_interface_id;
2328 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2329 #ifdef COMPRESSED_INTERFACE_BITMAP
2330 bitmap = g_malloc0 (bsize);
2332 bitmap = mono_domain_alloc0 (domain, bsize);
2335 if (! ARCH_USE_IMT) {
2336 /* initialize interface offsets */
2337 for (i = 0; i < class->interface_offsets_count; ++i) {
2338 int interface_id = class->interfaces_packed [i]->interface_id;
2339 int slot = class->interface_offsets_packed [i];
2340 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2343 for (i = 0; i < class->interface_offsets_count; ++i) {
2344 int interface_id = class->interfaces_packed [i]->interface_id;
2345 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2348 if (extra_interfaces) {
2349 int slot = class->vtable_size;
2355 /* Create trampolines for the methods of the interfaces */
2356 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2357 interf = list_item->data;
2359 if (! ARCH_USE_IMT) {
2360 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2362 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2366 while ((cm = mono_class_get_methods (interf, &iter)))
2367 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2369 slot += mono_class_num_methods (interf);
2371 if (! ARCH_USE_IMT) {
2372 g_slist_free (extra_interfaces);
2377 /* Now that the vtable is full, we can actually fill up the IMT */
2378 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2379 if (extra_interfaces) {
2380 g_slist_free (extra_interfaces);
2384 #ifdef COMPRESSED_INTERFACE_BITMAP
2385 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2386 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2387 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2390 pvt->interface_bitmap = bitmap;
2395 #endif /* DISABLE_REMOTING */
2398 * mono_class_field_is_special_static:
2400 * Returns whether @field is a thread/context static field.
2403 mono_class_field_is_special_static (MonoClassField *field)
2405 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2407 if (mono_field_is_deleted (field))
2409 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2410 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2417 * mono_class_field_get_special_static_type:
2418 * @field: The MonoClassField describing the field.
2420 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2421 * SPECIAL_STATIC_NONE otherwise.
2424 mono_class_field_get_special_static_type (MonoClassField *field)
2426 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2427 return SPECIAL_STATIC_NONE;
2428 if (mono_field_is_deleted (field))
2429 return SPECIAL_STATIC_NONE;
2430 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2431 return field_is_special_static (field->parent, field);
2432 return SPECIAL_STATIC_NONE;
2436 * mono_class_has_special_static_fields:
2438 * Returns whenever @klass has any thread/context static fields.
2441 mono_class_has_special_static_fields (MonoClass *klass)
2443 MonoClassField *field;
2447 while ((field = mono_class_get_fields (klass, &iter))) {
2448 g_assert (field->parent == klass);
2449 if (mono_class_field_is_special_static (field))
2456 #ifndef DISABLE_REMOTING
2458 * create_remote_class_key:
2459 * Creates an array of pointers that can be used as a hash key for a remote class.
2460 * The first element of the array is the number of pointers.
2463 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2468 if (remote_class == NULL) {
2469 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2470 key = g_malloc (sizeof(gpointer) * 3);
2471 key [0] = GINT_TO_POINTER (2);
2472 key [1] = mono_defaults.marshalbyrefobject_class;
2473 key [2] = extra_class;
2475 key = g_malloc (sizeof(gpointer) * 2);
2476 key [0] = GINT_TO_POINTER (1);
2477 key [1] = extra_class;
2480 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2481 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2482 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2483 key [1] = remote_class->proxy_class;
2485 // Keep the list of interfaces sorted
2486 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2487 if (extra_class && remote_class->interfaces [i] > extra_class) {
2488 key [j++] = extra_class;
2491 key [j] = remote_class->interfaces [i];
2494 key [j] = extra_class;
2496 // Replace the old class. The interface list is the same
2497 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2498 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2499 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2500 for (i = 0; i < remote_class->interface_count; i++)
2501 key [2 + i] = remote_class->interfaces [i];
2509 * copy_remote_class_key:
2511 * Make a copy of KEY in the domain and return the copy.
2514 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2516 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2517 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2519 memcpy (mp_key, key, key_size);
2525 * mono_remote_class:
2526 * @domain: the application domain
2527 * @class_name: name of the remote class
2529 * Creates and initializes a MonoRemoteClass object for a remote type.
2531 * Can raise an exception on failure.
2534 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2537 MonoRemoteClass *rc;
2538 gpointer* key, *mp_key;
2541 key = create_remote_class_key (NULL, proxy_class);
2543 mono_domain_lock (domain);
2544 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2548 mono_domain_unlock (domain);
2552 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2553 if (!mono_error_ok (&error)) {
2555 mono_domain_unlock (domain);
2556 mono_error_raise_exception (&error);
2559 mp_key = copy_remote_class_key (domain, key);
2563 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2564 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2565 rc->interface_count = 1;
2566 rc->interfaces [0] = proxy_class;
2567 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2569 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2570 rc->interface_count = 0;
2571 rc->proxy_class = proxy_class;
2574 rc->default_vtable = NULL;
2575 rc->xdomain_vtable = NULL;
2576 rc->proxy_class_name = name;
2577 #ifndef DISABLE_PERFCOUNTERS
2578 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2581 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2583 mono_domain_unlock (domain);
2588 * clone_remote_class:
2589 * Creates a copy of the remote_class, adding the provided class or interface
2591 static MonoRemoteClass*
2592 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2594 MonoRemoteClass *rc;
2595 gpointer* key, *mp_key;
2597 key = create_remote_class_key (remote_class, extra_class);
2598 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2604 mp_key = copy_remote_class_key (domain, key);
2608 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2610 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2611 rc->proxy_class = remote_class->proxy_class;
2612 rc->interface_count = remote_class->interface_count + 1;
2614 // Keep the list of interfaces sorted, since the hash key of
2615 // the remote class depends on this
2616 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2617 if (remote_class->interfaces [i] > extra_class && i == j)
2618 rc->interfaces [j++] = extra_class;
2619 rc->interfaces [j] = remote_class->interfaces [i];
2622 rc->interfaces [j] = extra_class;
2624 // Replace the old class. The interface array is the same
2625 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2626 rc->proxy_class = extra_class;
2627 rc->interface_count = remote_class->interface_count;
2628 if (rc->interface_count > 0)
2629 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2632 rc->default_vtable = NULL;
2633 rc->xdomain_vtable = NULL;
2634 rc->proxy_class_name = remote_class->proxy_class_name;
2636 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2642 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2644 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2645 mono_domain_lock (domain);
2646 if (rp->target_domain_id != -1) {
2647 if (remote_class->xdomain_vtable == NULL)
2648 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2649 mono_domain_unlock (domain);
2650 mono_loader_unlock ();
2651 return remote_class->xdomain_vtable;
2653 if (remote_class->default_vtable == NULL) {
2656 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2657 klass = mono_class_from_mono_type (type);
2659 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)))
2660 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2663 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2666 mono_domain_unlock (domain);
2667 mono_loader_unlock ();
2668 return remote_class->default_vtable;
2672 * mono_upgrade_remote_class:
2673 * @domain: the application domain
2674 * @tproxy: the proxy whose remote class has to be upgraded.
2675 * @klass: class to which the remote class can be casted.
2677 * Updates the vtable of the remote class by adding the necessary method slots
2678 * and interface offsets so it can be safely casted to klass. klass can be a
2679 * class or an interface.
2682 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2684 MonoTransparentProxy *tproxy;
2685 MonoRemoteClass *remote_class;
2686 gboolean redo_vtable;
2688 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2689 mono_domain_lock (domain);
2691 tproxy = (MonoTransparentProxy*) proxy_object;
2692 remote_class = tproxy->remote_class;
2694 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2697 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2698 if (remote_class->interfaces [i] == klass)
2699 redo_vtable = FALSE;
2702 redo_vtable = (remote_class->proxy_class != klass);
2706 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2707 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2710 mono_domain_unlock (domain);
2711 mono_loader_unlock ();
2713 #endif /* DISABLE_REMOTING */
2717 * mono_object_get_virtual_method:
2718 * @obj: object to operate on.
2721 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2722 * the instance of a callvirt of method.
2725 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2728 MonoMethod **vtable;
2729 gboolean is_proxy = FALSE;
2730 MonoMethod *res = NULL;
2732 klass = mono_object_class (obj);
2733 #ifndef DISABLE_REMOTING
2734 if (klass == mono_defaults.transparent_proxy_class) {
2735 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2740 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2743 mono_class_setup_vtable (klass);
2744 vtable = klass->vtable;
2746 if (method->slot == -1) {
2747 /* method->slot might not be set for instances of generic methods */
2748 if (method->is_inflated) {
2749 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2750 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2753 g_assert_not_reached ();
2757 /* check method->slot is a valid index: perform isinstance? */
2758 if (method->slot != -1) {
2759 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2761 gboolean variance_used = FALSE;
2762 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2763 g_assert (iface_offset > 0);
2764 res = vtable [iface_offset + method->slot];
2767 res = vtable [method->slot];
2771 #ifndef DISABLE_REMOTING
2773 /* It may be an interface, abstract class method or generic method */
2774 if (!res || mono_method_signature (res)->generic_param_count)
2777 /* generic methods demand invoke_with_check */
2778 if (mono_method_signature (res)->generic_param_count)
2779 res = mono_marshal_get_remoting_invoke_with_check (res);
2782 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2783 res = mono_cominterop_get_invoke (res);
2786 res = mono_marshal_get_remoting_invoke (res);
2791 if (method->is_inflated) {
2792 /* Have to inflate the result */
2793 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2803 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2805 g_error ("runtime invoke called on uninitialized runtime");
2809 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2812 * mono_runtime_invoke:
2813 * @method: method to invoke
2814 * @obJ: object instance
2815 * @params: arguments to the method
2816 * @exc: exception information.
2818 * Invokes the method represented by @method on the object @obj.
2820 * obj is the 'this' pointer, it should be NULL for static
2821 * methods, a MonoObject* for object instances and a pointer to
2822 * the value type for value types.
2824 * The params array contains the arguments to the method with the
2825 * same convention: MonoObject* pointers for object instances and
2826 * pointers to the value type otherwise.
2828 * From unmanaged code you'll usually use the
2829 * mono_runtime_invoke() variant.
2831 * Note that this function doesn't handle virtual methods for
2832 * you, it will exec the exact method you pass: we still need to
2833 * expose a function to lookup the derived class implementation
2834 * of a virtual method (there are examples of this in the code,
2837 * You can pass NULL as the exc argument if you don't want to
2838 * catch exceptions, otherwise, *exc will be set to the exception
2839 * thrown, if any. if an exception is thrown, you can't use the
2840 * MonoObject* result from the function.
2842 * If the method returns a value type, it is boxed in an object
2846 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2850 if (mono_runtime_get_no_exec ())
2851 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2853 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2854 mono_profiler_method_start_invoke (method);
2856 result = default_mono_runtime_invoke (method, obj, params, exc);
2858 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2859 mono_profiler_method_end_invoke (method);
2865 * mono_method_get_unmanaged_thunk:
2866 * @method: method to generate a thunk for.
2868 * Returns an unmanaged->managed thunk that can be used to call
2869 * a managed method directly from C.
2871 * The thunk's C signature closely matches the managed signature:
2873 * C#: public bool Equals (object obj);
2874 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2875 * MonoObject*, MonoException**);
2877 * The 1st ("this") parameter must not be used with static methods:
2879 * C#: public static bool ReferenceEquals (object a, object b);
2880 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2883 * The last argument must be a non-null pointer of a MonoException* pointer.
2884 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2885 * exception has been thrown in managed code. Otherwise it will point
2886 * to the MonoException* caught by the thunk. In this case, the result of
2887 * the thunk is undefined:
2889 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2890 * MonoException *ex = NULL;
2891 * Equals func = mono_method_get_unmanaged_thunk (method);
2892 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2894 * // handle exception
2897 * The calling convention of the thunk matches the platform's default
2898 * convention. This means that under Windows, C declarations must
2899 * contain the __stdcall attribute:
2901 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2902 * MonoObject*, MonoException**);
2906 * Value type arguments and return values are treated as they were objects:
2908 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2909 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2911 * Arguments must be properly boxed upon trunk's invocation, while return
2912 * values must be unboxed.
2915 mono_method_get_unmanaged_thunk (MonoMethod *method)
2917 method = mono_marshal_get_thunk_invoke_wrapper (method);
2918 return mono_compile_method (method);
2922 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2926 /* object fields cannot be byref, so we don't need a
2928 gpointer *p = (gpointer*)dest;
2935 case MONO_TYPE_BOOLEAN:
2937 case MONO_TYPE_U1: {
2938 guint8 *p = (guint8*)dest;
2939 *p = value ? *(guint8*)value : 0;
2944 case MONO_TYPE_CHAR: {
2945 guint16 *p = (guint16*)dest;
2946 *p = value ? *(guint16*)value : 0;
2949 #if SIZEOF_VOID_P == 4
2954 case MONO_TYPE_U4: {
2955 gint32 *p = (gint32*)dest;
2956 *p = value ? *(gint32*)value : 0;
2959 #if SIZEOF_VOID_P == 8
2964 case MONO_TYPE_U8: {
2965 gint64 *p = (gint64*)dest;
2966 *p = value ? *(gint64*)value : 0;
2969 case MONO_TYPE_R4: {
2970 float *p = (float*)dest;
2971 *p = value ? *(float*)value : 0;
2974 case MONO_TYPE_R8: {
2975 double *p = (double*)dest;
2976 *p = value ? *(double*)value : 0;
2979 case MONO_TYPE_STRING:
2980 case MONO_TYPE_SZARRAY:
2981 case MONO_TYPE_CLASS:
2982 case MONO_TYPE_OBJECT:
2983 case MONO_TYPE_ARRAY:
2984 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2986 case MONO_TYPE_FNPTR:
2987 case MONO_TYPE_PTR: {
2988 gpointer *p = (gpointer*)dest;
2989 *p = deref_pointer? *(gpointer*)value: value;
2992 case MONO_TYPE_VALUETYPE:
2993 /* note that 't' and 'type->type' can be different */
2994 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2995 t = mono_class_enum_basetype (type->data.klass)->type;
2998 MonoClass *class = mono_class_from_mono_type (type);
2999 int size = mono_class_value_size (class, NULL);
3001 mono_gc_bzero_atomic (dest, size);
3003 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3006 case MONO_TYPE_GENERICINST:
3007 t = type->data.generic_class->container_class->byval_arg.type;
3010 g_error ("got type %x", type->type);
3015 * mono_field_set_value:
3016 * @obj: Instance object
3017 * @field: MonoClassField describing the field to set
3018 * @value: The value to be set
3020 * Sets the value of the field described by @field in the object instance @obj
3021 * to the value passed in @value. This method should only be used for instance
3022 * fields. For static fields, use mono_field_static_set_value.
3024 * The value must be on the native format of the field type.
3027 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3031 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3033 dest = (char*)obj + field->offset;
3034 set_value (field->type, dest, value, FALSE);
3038 * mono_field_static_set_value:
3039 * @field: MonoClassField describing the field to set
3040 * @value: The value to be set
3042 * Sets the value of the static field described by @field
3043 * to the value passed in @value.
3045 * The value must be on the native format of the field type.
3048 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3052 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3053 /* you cant set a constant! */
3054 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3056 if (field->offset == -1) {
3057 /* Special static */
3060 mono_domain_lock (vt->domain);
3061 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3062 mono_domain_unlock (vt->domain);
3063 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3065 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3067 set_value (field->type, dest, value, FALSE);
3071 * mono_vtable_get_static_field_data:
3073 * Internal use function: return a pointer to the memory holding the static fields
3074 * for a class or NULL if there are no static fields.
3075 * This is exported only for use by the debugger.
3078 mono_vtable_get_static_field_data (MonoVTable *vt)
3080 if (!vt->has_static_fields)
3082 return vt->vtable [vt->klass->vtable_size];
3086 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3090 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3091 if (field->offset == -1) {
3092 /* Special static */
3095 mono_domain_lock (vt->domain);
3096 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3097 mono_domain_unlock (vt->domain);
3098 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3100 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3103 src = (guint8*)obj + field->offset;
3110 * mono_field_get_value:
3111 * @obj: Object instance
3112 * @field: MonoClassField describing the field to fetch information from
3113 * @value: pointer to the location where the value will be stored
3115 * Use this routine to get the value of the field @field in the object
3118 * The pointer provided by value must be of the field type, for reference
3119 * types this is a MonoObject*, for value types its the actual pointer to
3124 * mono_field_get_value (obj, int_field, &i);
3127 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3133 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3135 src = (char*)obj + field->offset;
3136 set_value (field->type, value, src, TRUE);
3140 * mono_field_get_value_object:
3141 * @domain: domain where the object will be created (if boxing)
3142 * @field: MonoClassField describing the field to fetch information from
3143 * @obj: The object instance for the field.
3145 * Returns: a new MonoObject with the value from the given field. If the
3146 * field represents a value type, the value is boxed.
3150 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3154 MonoVTable *vtable = NULL;
3156 gboolean is_static = FALSE;
3157 gboolean is_ref = FALSE;
3158 gboolean is_literal = FALSE;
3159 gboolean is_ptr = FALSE;
3161 MonoType *type = mono_field_get_type_checked (field, &error);
3163 if (!mono_error_ok (&error))
3164 mono_error_raise_exception (&error);
3166 switch (type->type) {
3167 case MONO_TYPE_STRING:
3168 case MONO_TYPE_OBJECT:
3169 case MONO_TYPE_CLASS:
3170 case MONO_TYPE_ARRAY:
3171 case MONO_TYPE_SZARRAY:
3176 case MONO_TYPE_BOOLEAN:
3179 case MONO_TYPE_CHAR:
3188 case MONO_TYPE_VALUETYPE:
3189 is_ref = type->byref;
3191 case MONO_TYPE_GENERICINST:
3192 is_ref = !mono_type_generic_inst_is_valuetype (type);
3198 g_error ("type 0x%x not handled in "
3199 "mono_field_get_value_object", type->type);
3203 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3206 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3210 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3211 if (!vtable->initialized)
3212 mono_runtime_class_init (vtable);
3220 get_default_field_value (domain, field, &o);
3221 } else if (is_static) {
3222 mono_field_static_get_value (vtable, field, &o);
3224 mono_field_get_value (obj, field, &o);
3230 static MonoMethod *m;
3236 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3237 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3243 get_default_field_value (domain, field, v);
3244 } else if (is_static) {
3245 mono_field_static_get_value (vtable, field, v);
3247 mono_field_get_value (obj, field, v);
3250 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3252 args [1] = mono_type_get_object (mono_domain_get (), type);
3254 return mono_runtime_invoke (m, NULL, args, NULL);
3257 /* boxed value type */
3258 klass = mono_class_from_mono_type (type);
3260 if (mono_class_is_nullable (klass))
3261 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3263 o = mono_object_new (domain, klass);
3264 v = ((gchar *) o) + sizeof (MonoObject);
3267 get_default_field_value (domain, field, v);
3268 } else if (is_static) {
3269 mono_field_static_get_value (vtable, field, v);
3271 mono_field_get_value (obj, field, v);
3278 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3281 const char *p = blob;
3282 mono_metadata_decode_blob_size (p, &p);
3285 case MONO_TYPE_BOOLEAN:
3288 *(guint8 *) value = *p;
3290 case MONO_TYPE_CHAR:
3293 *(guint16*) value = read16 (p);
3297 *(guint32*) value = read32 (p);
3301 *(guint64*) value = read64 (p);
3304 readr4 (p, (float*) value);
3307 readr8 (p, (double*) value);
3309 case MONO_TYPE_STRING:
3310 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3312 case MONO_TYPE_CLASS:
3313 *(gpointer*) value = NULL;
3317 g_warning ("type 0x%02x should not be in constant table", type);
3323 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3325 MonoTypeEnum def_type;
3328 data = mono_class_get_field_default_value (field, &def_type);
3329 mono_get_constant_value_from_blob (domain, def_type, data, value);
3333 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3337 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3339 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3340 get_default_field_value (vt->domain, field, value);
3344 if (field->offset == -1) {
3345 /* Special static */
3346 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3347 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3349 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3351 set_value (field->type, value, src, TRUE);
3355 * mono_field_static_get_value:
3356 * @vt: vtable to the object
3357 * @field: MonoClassField describing the field to fetch information from
3358 * @value: where the value is returned
3360 * Use this routine to get the value of the static field @field value.
3362 * The pointer provided by value must be of the field type, for reference
3363 * types this is a MonoObject*, for value types its the actual pointer to
3368 * mono_field_static_get_value (vt, int_field, &i);
3371 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3373 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3377 * mono_property_set_value:
3378 * @prop: MonoProperty to set
3379 * @obj: instance object on which to act
3380 * @params: parameters to pass to the propery
3381 * @exc: optional exception
3383 * Invokes the property's set method with the given arguments on the
3384 * object instance obj (or NULL for static properties).
3386 * You can pass NULL as the exc argument if you don't want to
3387 * catch exceptions, otherwise, *exc will be set to the exception
3388 * thrown, if any. if an exception is thrown, you can't use the
3389 * MonoObject* result from the function.
3392 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3394 default_mono_runtime_invoke (prop->set, obj, params, exc);
3398 * mono_property_get_value:
3399 * @prop: MonoProperty to fetch
3400 * @obj: instance object on which to act
3401 * @params: parameters to pass to the propery
3402 * @exc: optional exception
3404 * Invokes the property's get method with the given arguments on the
3405 * object instance obj (or NULL for static properties).
3407 * You can pass NULL as the exc argument if you don't want to
3408 * catch exceptions, otherwise, *exc will be set to the exception
3409 * thrown, if any. if an exception is thrown, you can't use the
3410 * MonoObject* result from the function.
3412 * Returns: the value from invoking the get method on the property.
3415 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3417 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3421 * mono_nullable_init:
3422 * @buf: The nullable structure to initialize.
3423 * @value: the value to initialize from
3424 * @klass: the type for the object
3426 * Initialize the nullable structure pointed to by @buf from @value which
3427 * should be a boxed value type. The size of @buf should be able to hold
3428 * as much data as the @klass->instance_size (which is the number of bytes
3429 * that will be copies).
3431 * Since Nullables have variable structure, we can not define a C
3432 * structure for them.
3435 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3437 MonoClass *param_class = klass->cast_class;
3439 mono_class_setup_fields_locking (klass);
3440 g_assert (klass->fields_inited);
3442 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3443 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3445 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3447 if (param_class->has_references)
3448 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3450 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3452 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3457 * mono_nullable_box:
3458 * @buf: The buffer representing the data to be boxed
3459 * @klass: the type to box it as.
3461 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3465 mono_nullable_box (guint8 *buf, MonoClass *klass)
3467 MonoClass *param_class = klass->cast_class;
3469 mono_class_setup_fields_locking (klass);
3470 g_assert (klass->fields_inited);
3472 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3473 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3475 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3476 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3477 if (param_class->has_references)
3478 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3480 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3488 * mono_get_delegate_invoke:
3489 * @klass: The delegate class
3491 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3494 mono_get_delegate_invoke (MonoClass *klass)
3498 /* This is called at runtime, so avoid the slower search in metadata */
3499 mono_class_setup_methods (klass);
3500 if (klass->exception_type)
3502 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3507 * mono_get_delegate_begin_invoke:
3508 * @klass: The delegate class
3510 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3513 mono_get_delegate_begin_invoke (MonoClass *klass)
3517 /* This is called at runtime, so avoid the slower search in metadata */
3518 mono_class_setup_methods (klass);
3519 if (klass->exception_type)
3521 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3526 * mono_get_delegate_end_invoke:
3527 * @klass: The delegate class
3529 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3532 mono_get_delegate_end_invoke (MonoClass *klass)
3536 /* This is called at runtime, so avoid the slower search in metadata */
3537 mono_class_setup_methods (klass);
3538 if (klass->exception_type)
3540 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3545 * mono_runtime_delegate_invoke:
3546 * @delegate: pointer to a delegate object.
3547 * @params: parameters for the delegate.
3548 * @exc: Pointer to the exception result.
3550 * Invokes the delegate method @delegate with the parameters provided.
3552 * You can pass NULL as the exc argument if you don't want to
3553 * catch exceptions, otherwise, *exc will be set to the exception
3554 * thrown, if any. if an exception is thrown, you can't use the
3555 * MonoObject* result from the function.
3558 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3561 MonoClass *klass = delegate->vtable->klass;
3563 im = mono_get_delegate_invoke (klass);
3565 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3567 return mono_runtime_invoke (im, delegate, params, exc);
3570 static char **main_args = NULL;
3571 static int num_main_args = 0;
3574 * mono_runtime_get_main_args:
3576 * Returns: a MonoArray with the arguments passed to the main program
3579 mono_runtime_get_main_args (void)
3583 MonoDomain *domain = mono_domain_get ();
3585 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3587 for (i = 0; i < num_main_args; ++i)
3588 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3594 free_main_args (void)
3598 for (i = 0; i < num_main_args; ++i)
3599 g_free (main_args [i]);
3606 * mono_runtime_set_main_args:
3607 * @argc: number of arguments from the command line
3608 * @argv: array of strings from the command line
3610 * Set the command line arguments from an embedding application that doesn't otherwise call
3611 * mono_runtime_run_main ().
3614 mono_runtime_set_main_args (int argc, char* argv[])
3619 main_args = g_new0 (char*, argc);
3620 num_main_args = argc;
3622 for (i = 0; i < argc; ++i) {
3625 utf8_arg = mono_utf8_from_external (argv[i]);
3626 if (utf8_arg == NULL) {
3627 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3628 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3632 main_args [i] = utf8_arg;
3639 * mono_runtime_run_main:
3640 * @method: the method to start the application with (usually Main)
3641 * @argc: number of arguments from the command line
3642 * @argv: array of strings from the command line
3643 * @exc: excetption results
3645 * Execute a standard Main() method (argc/argv contains the
3646 * executable name). This method also sets the command line argument value
3647 * needed by System.Environment.
3652 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3656 MonoArray *args = NULL;
3657 MonoDomain *domain = mono_domain_get ();
3658 gchar *utf8_fullpath;
3659 MonoMethodSignature *sig;
3661 g_assert (method != NULL);
3663 mono_thread_set_main (mono_thread_current ());
3665 main_args = g_new0 (char*, argc);
3666 num_main_args = argc;
3668 if (!g_path_is_absolute (argv [0])) {
3669 gchar *basename = g_path_get_basename (argv [0]);
3670 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3674 utf8_fullpath = mono_utf8_from_external (fullpath);
3675 if(utf8_fullpath == NULL) {
3676 /* Printing the arg text will cause glib to
3677 * whinge about "Invalid UTF-8", but at least
3678 * its relevant, and shows the problem text
3681 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3682 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3689 utf8_fullpath = mono_utf8_from_external (argv[0]);
3690 if(utf8_fullpath == NULL) {
3691 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3692 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3697 main_args [0] = utf8_fullpath;
3699 for (i = 1; i < argc; ++i) {
3702 utf8_arg=mono_utf8_from_external (argv[i]);
3703 if(utf8_arg==NULL) {
3704 /* Ditto the comment about Invalid UTF-8 here */
3705 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3706 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3710 main_args [i] = utf8_arg;
3715 sig = mono_method_signature (method);
3717 g_print ("Unable to load Main method.\n");
3721 if (sig->param_count) {
3722 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3723 for (i = 0; i < argc; ++i) {
3724 /* The encodings should all work, given that
3725 * we've checked all these args for the
3728 gchar *str = mono_utf8_from_external (argv [i]);
3729 MonoString *arg = mono_string_new (domain, str);
3730 mono_array_setref (args, i, arg);
3734 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3737 mono_assembly_set_main (method->klass->image->assembly);
3739 return mono_runtime_exec_main (method, args, exc);
3743 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3745 static MonoMethod *serialize_method;
3750 if (!serialize_method) {
3751 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3752 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3755 if (!serialize_method) {
3760 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3764 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3772 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3774 static MonoMethod *deserialize_method;
3779 if (!deserialize_method) {
3780 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3781 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3783 if (!deserialize_method) {
3790 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3797 #ifndef DISABLE_REMOTING
3799 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3801 static MonoMethod *get_proxy_method;
3803 MonoDomain *domain = mono_domain_get ();
3804 MonoRealProxy *real_proxy;
3805 MonoReflectionType *reflection_type;
3806 MonoTransparentProxy *transparent_proxy;
3808 if (!get_proxy_method)
3809 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3811 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3813 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3814 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3816 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3817 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3820 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3824 return (MonoObject*) transparent_proxy;
3826 #endif /* DISABLE_REMOTING */
3829 * mono_object_xdomain_representation
3831 * @target_domain: a domain
3832 * @exc: pointer to a MonoObject*
3834 * Creates a representation of obj in the domain target_domain. This
3835 * is either a copy of obj arrived through via serialization and
3836 * deserialization or a proxy, depending on whether the object is
3837 * serializable or marshal by ref. obj must not be in target_domain.
3839 * If the object cannot be represented in target_domain, NULL is
3840 * returned and *exc is set to an appropriate exception.
3843 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3845 MonoObject *deserialized = NULL;
3846 gboolean failure = FALSE;
3850 #ifndef DISABLE_REMOTING
3851 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3852 deserialized = make_transparent_proxy (obj, &failure, exc);
3857 MonoDomain *domain = mono_domain_get ();
3858 MonoObject *serialized;
3860 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3861 serialized = serialize_object (obj, &failure, exc);
3862 mono_domain_set_internal_with_options (target_domain, FALSE);
3864 deserialized = deserialize_object (serialized, &failure, exc);
3865 if (domain != target_domain)
3866 mono_domain_set_internal_with_options (domain, FALSE);
3869 return deserialized;
3872 /* Used in call_unhandled_exception_delegate */
3874 create_unhandled_exception_eventargs (MonoObject *exc)
3878 MonoMethod *method = NULL;
3879 MonoBoolean is_terminating = TRUE;
3882 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3885 mono_class_init (klass);
3887 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3888 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3892 args [1] = &is_terminating;
3894 obj = mono_object_new (mono_domain_get (), klass);
3895 mono_runtime_invoke (method, obj, args, NULL);
3900 /* Used in mono_unhandled_exception */
3902 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3903 MonoObject *e = NULL;
3905 MonoDomain *current_domain = mono_domain_get ();
3907 if (domain != current_domain)
3908 mono_domain_set_internal_with_options (domain, FALSE);
3910 g_assert (domain == mono_object_domain (domain->domain));
3912 if (mono_object_domain (exc) != domain) {
3913 MonoObject *serialization_exc;
3915 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3917 if (serialization_exc) {
3919 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3922 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3923 "System.Runtime.Serialization", "SerializationException",
3924 "Could not serialize unhandled exception.");
3928 g_assert (mono_object_domain (exc) == domain);
3930 pa [0] = domain->domain;
3931 pa [1] = create_unhandled_exception_eventargs (exc);
3932 mono_runtime_delegate_invoke (delegate, pa, &e);
3934 if (domain != current_domain)
3935 mono_domain_set_internal_with_options (current_domain, FALSE);
3939 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3940 if (!mono_error_ok (&error)) {
3941 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3942 mono_error_cleanup (&error);
3944 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3950 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3953 * mono_runtime_unhandled_exception_policy_set:
3954 * @policy: the new policy
3956 * This is a VM internal routine.
3958 * Sets the runtime policy for handling unhandled exceptions.
3961 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3962 runtime_unhandled_exception_policy = policy;
3966 * mono_runtime_unhandled_exception_policy_get:
3968 * This is a VM internal routine.
3970 * Gets the runtime policy for handling unhandled exceptions.
3972 MonoRuntimeUnhandledExceptionPolicy
3973 mono_runtime_unhandled_exception_policy_get (void) {
3974 return runtime_unhandled_exception_policy;
3978 * mono_unhandled_exception:
3979 * @exc: exception thrown
3981 * This is a VM internal routine.
3983 * We call this function when we detect an unhandled exception
3984 * in the default domain.
3986 * It invokes the * UnhandledException event in AppDomain or prints
3987 * a warning to the console
3990 mono_unhandled_exception (MonoObject *exc)
3992 MonoDomain *current_domain = mono_domain_get ();
3993 MonoDomain *root_domain = mono_get_root_domain ();
3994 MonoClassField *field;
3995 MonoObject *current_appdomain_delegate;
3996 MonoObject *root_appdomain_delegate;
3998 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3999 "UnhandledException");
4002 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4003 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4004 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4005 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4006 if (current_domain != root_domain) {
4007 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4009 current_appdomain_delegate = NULL;
4012 /* set exitcode only if we will abort the process */
4013 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4015 mono_environment_exitcode_set (1);
4016 mono_print_unhandled_exception (exc);
4018 if (root_appdomain_delegate) {
4019 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4021 if (current_appdomain_delegate) {
4022 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4029 * mono_runtime_exec_managed_code:
4030 * @domain: Application domain
4031 * @main_func: function to invoke from the execution thread
4032 * @main_args: parameter to the main_func
4034 * Launch a new thread to execute a function
4036 * main_func is called back from the thread with main_args as the
4037 * parameter. The callback function is expected to start Main()
4038 * eventually. This function then waits for all managed threads to
4040 * It is not necesseray anymore to execute managed code in a subthread,
4041 * so this function should not be used anymore by default: just
4042 * execute the code and then call mono_thread_manage ().
4045 mono_runtime_exec_managed_code (MonoDomain *domain,
4046 MonoMainThreadFunc main_func,
4049 mono_thread_create (domain, main_func, main_args);
4051 mono_thread_manage ();
4055 * Execute a standard Main() method (args doesn't contain the
4059 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4064 MonoCustomAttrInfo* cinfo;
4065 gboolean has_stathread_attribute;
4066 MonoInternalThread* thread = mono_thread_internal_current ();
4072 domain = mono_object_domain (args);
4073 if (!domain->entry_assembly) {
4075 MonoAssembly *assembly;
4077 assembly = method->klass->image->assembly;
4078 domain->entry_assembly = assembly;
4079 /* Domains created from another domain already have application_base and configuration_file set */
4080 if (domain->setup->application_base == NULL) {
4081 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4084 if (domain->setup->configuration_file == NULL) {
4085 str = g_strconcat (assembly->image->name, ".config", NULL);
4086 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4088 mono_set_private_bin_path_from_config (domain);
4092 cinfo = mono_custom_attrs_from_method (method);
4094 static MonoClass *stathread_attribute = NULL;
4095 if (!stathread_attribute)
4096 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4097 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4099 mono_custom_attrs_free (cinfo);
4101 has_stathread_attribute = FALSE;
4103 if (has_stathread_attribute) {
4104 thread->apartment_state = ThreadApartmentState_STA;
4106 thread->apartment_state = ThreadApartmentState_MTA;
4108 mono_thread_init_apartment_state ();
4110 /* FIXME: check signature of method */
4111 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4113 res = mono_runtime_invoke (method, NULL, pa, exc);
4115 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4119 mono_environment_exitcode_set (rval);
4121 mono_runtime_invoke (method, NULL, pa, exc);
4125 /* If the return type of Main is void, only
4126 * set the exitcode if an exception was thrown
4127 * (we don't want to blow away an
4128 * explicitly-set exit code)
4131 mono_environment_exitcode_set (rval);
4139 * mono_install_runtime_invoke:
4140 * @func: Function to install
4142 * This is a VM internal routine
4145 mono_install_runtime_invoke (MonoInvokeFunc func)
4147 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4152 * mono_runtime_invoke_array:
4153 * @method: method to invoke
4154 * @obJ: object instance
4155 * @params: arguments to the method
4156 * @exc: exception information.
4158 * Invokes the method represented by @method on the object @obj.
4160 * obj is the 'this' pointer, it should be NULL for static
4161 * methods, a MonoObject* for object instances and a pointer to
4162 * the value type for value types.
4164 * The params array contains the arguments to the method with the
4165 * same convention: MonoObject* pointers for object instances and
4166 * pointers to the value type otherwise. The _invoke_array
4167 * variant takes a C# object[] as the params argument (MonoArray
4168 * *params): in this case the value types are boxed inside the
4169 * respective reference representation.
4171 * From unmanaged code you'll usually use the
4172 * mono_runtime_invoke() variant.
4174 * Note that this function doesn't handle virtual methods for
4175 * you, it will exec the exact method you pass: we still need to
4176 * expose a function to lookup the derived class implementation
4177 * of a virtual method (there are examples of this in the code,
4180 * You can pass NULL as the exc argument if you don't want to
4181 * catch exceptions, otherwise, *exc will be set to the exception
4182 * thrown, if any. if an exception is thrown, you can't use the
4183 * MonoObject* result from the function.
4185 * If the method returns a value type, it is boxed in an object
4189 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4192 MonoMethodSignature *sig = mono_method_signature (method);
4193 gpointer *pa = NULL;
4196 gboolean has_byref_nullables = FALSE;
4198 if (NULL != params) {
4199 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4200 for (i = 0; i < mono_array_length (params); i++) {
4201 MonoType *t = sig->params [i];
4207 case MONO_TYPE_BOOLEAN:
4210 case MONO_TYPE_CHAR:
4219 case MONO_TYPE_VALUETYPE:
4220 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4221 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4222 pa [i] = mono_array_get (params, MonoObject*, i);
4224 has_byref_nullables = TRUE;
4226 /* MS seems to create the objects if a null is passed in */
4227 if (!mono_array_get (params, MonoObject*, i))
4228 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4232 * We can't pass the unboxed vtype byref to the callee, since
4233 * that would mean the callee would be able to modify boxed
4234 * primitive types. So we (and MS) make a copy of the boxed
4235 * object, pass that to the callee, and replace the original
4236 * boxed object in the arg array with the copy.
4238 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4239 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4240 mono_array_setref (params, i, copy);
4243 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4246 case MONO_TYPE_STRING:
4247 case MONO_TYPE_OBJECT:
4248 case MONO_TYPE_CLASS:
4249 case MONO_TYPE_ARRAY:
4250 case MONO_TYPE_SZARRAY:
4252 pa [i] = mono_array_addr (params, MonoObject*, i);
4253 // FIXME: I need to check this code path
4255 pa [i] = mono_array_get (params, MonoObject*, i);
4257 case MONO_TYPE_GENERICINST:
4259 t = &t->data.generic_class->container_class->this_arg;
4261 t = &t->data.generic_class->container_class->byval_arg;
4263 case MONO_TYPE_PTR: {
4266 /* The argument should be an IntPtr */
4267 arg = mono_array_get (params, MonoObject*, i);
4271 g_assert (arg->vtable->klass == mono_defaults.int_class);
4272 pa [i] = ((MonoIntPtr*)arg)->m_value;
4277 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4282 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4285 if (mono_class_is_nullable (method->klass)) {
4286 /* Need to create a boxed vtype instead */
4292 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4296 obj = mono_object_new (mono_domain_get (), method->klass);
4297 g_assert (obj); /*maybe we should raise a TLE instead?*/
4298 #ifndef DISABLE_REMOTING
4299 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4300 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4303 if (method->klass->valuetype)
4304 o = mono_object_unbox (obj);
4307 } else if (method->klass->valuetype) {
4308 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4311 mono_runtime_invoke (method, o, pa, exc);
4314 if (mono_class_is_nullable (method->klass)) {
4315 MonoObject *nullable;
4317 /* Convert the unboxed vtype into a Nullable structure */
4318 nullable = mono_object_new (mono_domain_get (), method->klass);
4320 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4321 obj = mono_object_unbox (nullable);
4324 /* obj must be already unboxed if needed */
4325 res = mono_runtime_invoke (method, obj, pa, exc);
4327 if (sig->ret->type == MONO_TYPE_PTR) {
4328 MonoClass *pointer_class;
4329 static MonoMethod *box_method;
4331 MonoObject *box_exc;
4334 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4335 * convert it to a Pointer object.
4337 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4339 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4341 g_assert (res->vtable->klass == mono_defaults.int_class);
4342 box_args [0] = ((MonoIntPtr*)res)->m_value;
4343 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4344 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4345 g_assert (!box_exc);
4348 if (has_byref_nullables) {
4350 * The runtime invoke wrapper already converted byref nullables back,
4351 * and stored them in pa, we just need to copy them back to the
4354 for (i = 0; i < mono_array_length (params); i++) {
4355 MonoType *t = sig->params [i];
4357 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4358 mono_array_setref (params, i, pa [i]);
4367 arith_overflow (void)
4369 mono_raise_exception (mono_get_exception_overflow ());
4373 * mono_object_allocate:
4374 * @size: number of bytes to allocate
4376 * This is a very simplistic routine until we have our GC-aware
4379 * Returns: an allocated object of size @size, or NULL on failure.
4381 static inline void *
4382 mono_object_allocate (size_t size, MonoVTable *vtable)
4385 ALLOC_OBJECT (o, vtable, size);
4391 * mono_object_allocate_ptrfree:
4392 * @size: number of bytes to allocate
4394 * Note that the memory allocated is not zeroed.
4395 * Returns: an allocated object of size @size, or NULL on failure.
4397 static inline void *
4398 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4401 ALLOC_PTRFREE (o, vtable, size);
4405 static inline void *
4406 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4409 ALLOC_TYPED (o, size, vtable);
4416 * @klass: the class of the object that we want to create
4418 * Returns: a newly created object whose definition is
4419 * looked up using @klass. This will not invoke any constructors,
4420 * so the consumer of this routine has to invoke any constructors on
4421 * its own to initialize the object.
4423 * It returns NULL on failure.
4426 mono_object_new (MonoDomain *domain, MonoClass *klass)
4430 MONO_ARCH_SAVE_REGS;
4431 vtable = mono_class_vtable (domain, klass);
4434 return mono_object_new_specific (vtable);
4438 * mono_object_new_pinned:
4440 * Same as mono_object_new, but the returned object will be pinned.
4441 * For SGEN, these objects will only be freed at appdomain unload.
4444 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4448 MONO_ARCH_SAVE_REGS;
4449 vtable = mono_class_vtable (domain, klass);
4454 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4456 return mono_object_new_specific (vtable);
4461 * mono_object_new_specific:
4462 * @vtable: the vtable of the object that we want to create
4464 * Returns: A newly created object with class and domain specified
4468 mono_object_new_specific (MonoVTable *vtable)
4472 MONO_ARCH_SAVE_REGS;
4474 /* check for is_com_object for COM Interop */
4475 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4478 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4481 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4484 mono_class_init (klass);
4486 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4488 vtable->domain->create_proxy_for_type_method = im;
4491 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4493 o = mono_runtime_invoke (im, NULL, pa, NULL);
4494 if (o != NULL) return o;
4497 return mono_object_new_alloc_specific (vtable);
4501 mono_object_new_alloc_specific (MonoVTable *vtable)
4505 if (!vtable->klass->has_references) {
4506 o = mono_object_new_ptrfree (vtable);
4507 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4508 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4510 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4511 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4513 if (G_UNLIKELY (vtable->klass->has_finalize))
4514 mono_object_register_finalizer (o);
4516 if (G_UNLIKELY (profile_allocs))
4517 mono_profiler_allocation (o, vtable->klass);
4522 mono_object_new_fast (MonoVTable *vtable)
4525 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4530 mono_object_new_ptrfree (MonoVTable *vtable)
4533 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4534 #if NEED_TO_ZERO_PTRFREE
4535 /* an inline memset is much faster for the common vcase of small objects
4536 * note we assume the allocated size is a multiple of sizeof (void*).
4538 if (vtable->klass->instance_size < 128) {
4540 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4541 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4547 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4554 mono_object_new_ptrfree_box (MonoVTable *vtable)
4557 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4558 /* the object will be boxed right away, no need to memzero it */
4563 * mono_class_get_allocation_ftn:
4565 * @for_box: the object will be used for boxing
4566 * @pass_size_in_words:
4568 * Return the allocation function appropriate for the given class.
4572 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4574 *pass_size_in_words = FALSE;
4576 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4577 profile_allocs = FALSE;
4579 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4580 return mono_object_new_specific;
4582 if (!vtable->klass->has_references) {
4583 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4585 return mono_object_new_ptrfree_box;
4586 return mono_object_new_ptrfree;
4589 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4591 return mono_object_new_fast;
4594 * FIXME: This is actually slower than mono_object_new_fast, because
4595 * of the overhead of parameter passing.
4598 *pass_size_in_words = TRUE;
4599 #ifdef GC_REDIRECT_TO_LOCAL
4600 return GC_local_gcj_fast_malloc;
4602 return GC_gcj_fast_malloc;
4607 return mono_object_new_specific;
4611 * mono_object_new_from_token:
4612 * @image: Context where the type_token is hosted
4613 * @token: a token of the type that we want to create
4615 * Returns: A newly created object whose definition is
4616 * looked up using @token in the @image image
4619 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4624 class = mono_class_get_checked (image, token, &error);
4625 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4627 return mono_object_new (domain, class);
4632 * mono_object_clone:
4633 * @obj: the object to clone
4635 * Returns: A newly created object who is a shallow copy of @obj
4638 mono_object_clone (MonoObject *obj)
4641 int size = obj->vtable->klass->instance_size;
4643 if (obj->vtable->klass->rank)
4644 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4646 o = mono_object_allocate (size, obj->vtable);
4648 if (obj->vtable->klass->has_references) {
4649 mono_gc_wbarrier_object_copy (o, obj);
4651 int size = obj->vtable->klass->instance_size;
4652 /* do not copy the sync state */
4653 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4655 if (G_UNLIKELY (profile_allocs))
4656 mono_profiler_allocation (o, obj->vtable->klass);
4658 if (obj->vtable->klass->has_finalize)
4659 mono_object_register_finalizer (o);
4664 * mono_array_full_copy:
4665 * @src: source array to copy
4666 * @dest: destination array
4668 * Copies the content of one array to another with exactly the same type and size.
4671 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4674 MonoClass *klass = src->obj.vtable->klass;
4676 MONO_ARCH_SAVE_REGS;
4678 g_assert (klass == dest->obj.vtable->klass);
4680 size = mono_array_length (src);
4681 g_assert (size == mono_array_length (dest));
4682 size *= mono_array_element_size (klass);
4684 if (klass->element_class->valuetype) {
4685 if (klass->element_class->has_references)
4686 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4688 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4690 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4693 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4698 * mono_array_clone_in_domain:
4699 * @domain: the domain in which the array will be cloned into
4700 * @array: the array to clone
4702 * This routine returns a copy of the array that is hosted on the
4703 * specified MonoDomain.
4706 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4711 MonoClass *klass = array->obj.vtable->klass;
4713 MONO_ARCH_SAVE_REGS;
4715 if (array->bounds == NULL) {
4716 size = mono_array_length (array);
4717 o = mono_array_new_full (domain, klass, &size, NULL);
4719 size *= mono_array_element_size (klass);
4721 if (klass->element_class->valuetype) {
4722 if (klass->element_class->has_references)
4723 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4725 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4727 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4730 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4735 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4736 size = mono_array_element_size (klass);
4737 for (i = 0; i < klass->rank; ++i) {
4738 sizes [i] = array->bounds [i].length;
4739 size *= array->bounds [i].length;
4740 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4742 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4744 if (klass->element_class->valuetype) {
4745 if (klass->element_class->has_references)
4746 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4748 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4750 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4753 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4761 * @array: the array to clone
4763 * Returns: A newly created array who is a shallow copy of @array
4766 mono_array_clone (MonoArray *array)
4768 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4771 /* helper macros to check for overflow when calculating the size of arrays */
4772 #ifdef MONO_BIG_ARRAYS
4773 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4774 #define MYGUINT_MAX MYGUINT64_MAX
4775 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4776 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4777 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4778 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4779 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4781 #define MYGUINT32_MAX 4294967295U
4782 #define MYGUINT_MAX MYGUINT32_MAX
4783 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4784 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4785 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4786 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4787 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4791 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4795 byte_len = mono_array_element_size (class);
4796 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4799 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4801 byte_len += sizeof (MonoArray);
4809 * mono_array_new_full:
4810 * @domain: domain where the object is created
4811 * @array_class: array class
4812 * @lengths: lengths for each dimension in the array
4813 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4815 * This routine creates a new array objects with the given dimensions,
4816 * lower bounds and type.
4819 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4821 uintptr_t byte_len = 0, len, bounds_size;
4824 MonoArrayBounds *bounds;
4828 if (!array_class->inited)
4829 mono_class_init (array_class);
4833 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4834 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4836 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4840 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4842 for (i = 0; i < array_class->rank; ++i) {
4843 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4845 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4846 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4851 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4852 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4856 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4857 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4858 byte_len = (byte_len + 3) & ~3;
4859 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4860 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4861 byte_len += bounds_size;
4864 * Following three lines almost taken from mono_object_new ():
4865 * they need to be kept in sync.
4867 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4868 #ifndef HAVE_SGEN_GC
4869 if (!array_class->has_references) {
4870 o = mono_object_allocate_ptrfree (byte_len, vtable);
4871 #if NEED_TO_ZERO_PTRFREE
4872 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4874 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4875 o = mono_object_allocate_spec (byte_len, vtable);
4877 o = mono_object_allocate (byte_len, vtable);
4880 array = (MonoArray*)o;
4881 array->max_length = len;
4884 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4885 array->bounds = bounds;
4889 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4891 o = mono_gc_alloc_vector (vtable, byte_len, len);
4892 array = (MonoArray*)o;
4894 bounds = array->bounds;
4898 for (i = 0; i < array_class->rank; ++i) {
4899 bounds [i].length = lengths [i];
4901 bounds [i].lower_bound = lower_bounds [i];
4905 if (G_UNLIKELY (profile_allocs))
4906 mono_profiler_allocation (o, array_class);
4913 * @domain: domain where the object is created
4914 * @eclass: element class
4915 * @n: number of array elements
4917 * This routine creates a new szarray with @n elements of type @eclass.
4920 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4924 MONO_ARCH_SAVE_REGS;
4926 ac = mono_array_class_get (eclass, 1);
4929 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4933 * mono_array_new_specific:
4934 * @vtable: a vtable in the appropriate domain for an initialized class
4935 * @n: number of array elements
4937 * This routine is a fast alternative to mono_array_new() for code which
4938 * can be sure about the domain it operates in.
4941 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4947 MONO_ARCH_SAVE_REGS;
4949 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4954 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4955 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4958 #ifndef HAVE_SGEN_GC
4959 if (!vtable->klass->has_references) {
4960 o = mono_object_allocate_ptrfree (byte_len, vtable);
4961 #if NEED_TO_ZERO_PTRFREE
4962 ((MonoArray*)o)->bounds = NULL;
4963 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4965 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4966 o = mono_object_allocate_spec (byte_len, vtable);
4968 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4969 o = mono_object_allocate (byte_len, vtable);
4972 ao = (MonoArray *)o;
4975 o = mono_gc_alloc_vector (vtable, byte_len, n);
4979 if (G_UNLIKELY (profile_allocs))
4980 mono_profiler_allocation (o, vtable->klass);
4986 * mono_string_new_utf16:
4987 * @text: a pointer to an utf16 string
4988 * @len: the length of the string
4990 * Returns: A newly created string object which contains @text.
4993 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4997 s = mono_string_new_size (domain, len);
4998 g_assert (s != NULL);
5000 memcpy (mono_string_chars (s), text, len * 2);
5006 * mono_string_new_utf32:
5007 * @text: a pointer to an utf32 string
5008 * @len: the length of the string
5010 * Returns: A newly created string object which contains @text.
5013 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5016 mono_unichar2 *utf16_output = NULL;
5017 gint32 utf16_len = 0;
5018 GError *error = NULL;
5019 glong items_written;
5021 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5024 g_error_free (error);
5026 while (utf16_output [utf16_len]) utf16_len++;
5028 s = mono_string_new_size (domain, utf16_len);
5029 g_assert (s != NULL);
5031 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5033 g_free (utf16_output);
5039 * mono_string_new_size:
5040 * @text: a pointer to an utf16 string
5041 * @len: the length of the string
5043 * Returns: A newly created string object of @len
5046 mono_string_new_size (MonoDomain *domain, gint32 len)
5052 /* check for overflow */
5053 if (len < 0 || len > ((SIZE_MAX - offsetof (MonoString, chars) - 2) / 2))
5054 mono_gc_out_of_memory (-1);
5056 size = (offsetof (MonoString, chars) + ((len + 1) * 2));
5057 g_assert (size > 0);
5059 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5062 #ifndef HAVE_SGEN_GC
5063 s = mono_object_allocate_ptrfree (size, vtable);
5067 s = mono_gc_alloc_string (vtable, size, len);
5069 #if NEED_TO_ZERO_PTRFREE
5072 if (G_UNLIKELY (profile_allocs))
5073 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5079 * mono_string_new_len:
5080 * @text: a pointer to an utf8 string
5081 * @length: number of bytes in @text to consider
5083 * Returns: A newly created string object which contains @text.
5086 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5088 GError *error = NULL;
5089 MonoString *o = NULL;
5091 glong items_written;
5093 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5096 o = mono_string_new_utf16 (domain, ut, items_written);
5098 g_error_free (error);
5107 * @text: a pointer to an utf8 string
5109 * Returns: A newly created string object which contains @text.
5112 mono_string_new (MonoDomain *domain, const char *text)
5114 GError *error = NULL;
5115 MonoString *o = NULL;
5117 glong items_written;
5122 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5125 o = mono_string_new_utf16 (domain, ut, items_written);
5127 g_error_free (error);
5130 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5135 MonoString *o = NULL;
5137 if (!g_utf8_validate (text, -1, &end))
5140 len = g_utf8_strlen (text, -1);
5141 o = mono_string_new_size (domain, len);
5142 str = mono_string_chars (o);
5144 while (text < end) {
5145 *str++ = g_utf8_get_char (text);
5146 text = g_utf8_next_char (text);
5153 * mono_string_new_wrapper:
5154 * @text: pointer to utf8 characters.
5156 * Helper function to create a string object from @text in the current domain.
5159 mono_string_new_wrapper (const char *text)
5161 MonoDomain *domain = mono_domain_get ();
5163 MONO_ARCH_SAVE_REGS;
5166 return mono_string_new (domain, text);
5173 * @class: the class of the value
5174 * @value: a pointer to the unboxed data
5176 * Returns: A newly created object which contains @value.
5179 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5185 g_assert (class->valuetype);
5186 if (mono_class_is_nullable (class))
5187 return mono_nullable_box (value, class);
5189 vtable = mono_class_vtable (domain, class);
5192 size = mono_class_instance_size (class);
5193 res = mono_object_new_alloc_specific (vtable);
5194 if (G_UNLIKELY (profile_allocs))
5195 mono_profiler_allocation (res, class);
5197 size = size - sizeof (MonoObject);
5200 g_assert (size == mono_class_value_size (class, NULL));
5201 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5203 #if NO_UNALIGNED_ACCESS
5204 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5208 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5211 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5214 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5217 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5220 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5224 if (class->has_finalize)
5225 mono_object_register_finalizer (res);
5231 * @dest: destination pointer
5232 * @src: source pointer
5233 * @klass: a valuetype class
5235 * Copy a valuetype from @src to @dest. This function must be used
5236 * when @klass contains references fields.
5239 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5241 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5245 * mono_value_copy_array:
5246 * @dest: destination array
5247 * @dest_idx: index in the @dest array
5248 * @src: source pointer
5249 * @count: number of items
5251 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5252 * This function must be used when @klass contains references fields.
5253 * Overlap is handled.
5256 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5258 int size = mono_array_element_size (dest->obj.vtable->klass);
5259 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5260 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5261 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5265 * mono_object_get_domain:
5266 * @obj: object to query
5268 * Returns: the MonoDomain where the object is hosted
5271 mono_object_get_domain (MonoObject *obj)
5273 return mono_object_domain (obj);
5277 * mono_object_get_class:
5278 * @obj: object to query
5280 * Returns: the MonOClass of the object.
5283 mono_object_get_class (MonoObject *obj)
5285 return mono_object_class (obj);
5288 * mono_object_get_size:
5289 * @o: object to query
5291 * Returns: the size, in bytes, of @o
5294 mono_object_get_size (MonoObject* o)
5296 MonoClass* klass = mono_object_class (o);
5297 if (klass == mono_defaults.string_class) {
5298 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5299 } else if (o->vtable->rank) {
5300 MonoArray *array = (MonoArray*)o;
5301 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5302 if (array->bounds) {
5305 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5309 return mono_class_instance_size (klass);
5314 * mono_object_unbox:
5315 * @obj: object to unbox
5317 * Returns: a pointer to the start of the valuetype boxed in this
5320 * This method will assert if the object passed is not a valuetype.
5323 mono_object_unbox (MonoObject *obj)
5325 /* add assert for valuetypes? */
5326 g_assert (obj->vtable->klass->valuetype);
5327 return ((char*)obj) + sizeof (MonoObject);
5331 * mono_object_isinst:
5333 * @klass: a pointer to a class
5335 * Returns: @obj if @obj is derived from @klass
5338 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5341 mono_class_init (klass);
5343 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5344 return mono_object_isinst_mbyref (obj, klass);
5349 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5353 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5362 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5363 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5367 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5368 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5371 MonoClass *oklass = vt->klass;
5372 if (mono_class_is_transparent_proxy (oklass))
5373 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5375 mono_class_setup_supertypes (klass);
5376 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5379 #ifndef DISABLE_REMOTING
5380 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5382 MonoDomain *domain = mono_domain_get ();
5384 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5385 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5386 MonoMethod *im = NULL;
5389 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5390 im = mono_object_get_virtual_method (rp, im);
5393 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5396 res = mono_runtime_invoke (im, rp, pa, NULL);
5398 if (*(MonoBoolean *) mono_object_unbox(res)) {
5399 /* Update the vtable of the remote type, so it can safely cast to this new type */
5400 mono_upgrade_remote_class (domain, obj, klass);
5404 #endif /* DISABLE_REMOTING */
5409 * mono_object_castclass_mbyref:
5411 * @klass: a pointer to a class
5413 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5416 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5418 if (!obj) return NULL;
5419 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5421 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5423 "InvalidCastException"));
5428 MonoDomain *orig_domain;
5434 str_lookup (MonoDomain *domain, gpointer user_data)
5436 LDStrInfo *info = user_data;
5437 if (info->res || domain == info->orig_domain)
5439 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5445 mono_string_get_pinned (MonoString *str)
5449 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5450 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5452 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5453 news->length = mono_string_length (str);
5459 #define mono_string_get_pinned(str) (str)
5463 mono_string_is_interned_lookup (MonoString *str, int insert)
5465 MonoGHashTable *ldstr_table;
5469 domain = ((MonoObject *)str)->vtable->domain;
5470 ldstr_table = domain->ldstr_table;
5472 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5477 str = mono_string_get_pinned (str);
5479 mono_g_hash_table_insert (ldstr_table, str, str);
5483 LDStrInfo ldstr_info;
5484 ldstr_info.orig_domain = domain;
5485 ldstr_info.ins = str;
5486 ldstr_info.res = NULL;
5488 mono_domain_foreach (str_lookup, &ldstr_info);
5489 if (ldstr_info.res) {
5491 * the string was already interned in some other domain:
5492 * intern it in the current one as well.
5494 mono_g_hash_table_insert (ldstr_table, str, str);
5504 * mono_string_is_interned:
5505 * @o: String to probe
5507 * Returns whether the string has been interned.
5510 mono_string_is_interned (MonoString *o)
5512 return mono_string_is_interned_lookup (o, FALSE);
5516 * mono_string_intern:
5517 * @o: String to intern
5519 * Interns the string passed.
5520 * Returns: The interned string.
5523 mono_string_intern (MonoString *str)
5525 return mono_string_is_interned_lookup (str, TRUE);
5530 * @domain: the domain where the string will be used.
5531 * @image: a metadata context
5532 * @idx: index into the user string table.
5534 * Implementation for the ldstr opcode.
5535 * Returns: a loaded string from the @image/@idx combination.
5538 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5540 MONO_ARCH_SAVE_REGS;
5542 if (image->dynamic) {
5543 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5546 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5547 return NULL; /*FIXME we should probably be raising an exception here*/
5548 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5553 * mono_ldstr_metadata_sig
5554 * @domain: the domain for the string
5555 * @sig: the signature of a metadata string
5557 * Returns: a MonoString for a string stored in the metadata
5560 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5562 const char *str = sig;
5563 MonoString *o, *interned;
5566 len2 = mono_metadata_decode_blob_size (str, &str);
5569 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5570 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5573 guint16 *p2 = (guint16*)mono_string_chars (o);
5574 for (i = 0; i < len2; ++i) {
5575 *p2 = GUINT16_FROM_LE (*p2);
5581 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5583 /* o will get garbage collected */
5587 o = mono_string_get_pinned (o);
5589 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5596 * mono_string_to_utf8:
5597 * @s: a System.String
5599 * Returns the UTF8 representation for @s.
5600 * The resulting buffer needs to be freed with mono_free().
5602 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5605 mono_string_to_utf8 (MonoString *s)
5608 char *result = mono_string_to_utf8_checked (s, &error);
5610 if (!mono_error_ok (&error))
5611 mono_error_raise_exception (&error);
5616 * mono_string_to_utf8_checked:
5617 * @s: a System.String
5618 * @error: a MonoError.
5620 * Converts a MonoString to its UTF8 representation. May fail; check
5621 * @error to determine whether the conversion was successful.
5622 * The resulting buffer should be freed with mono_free().
5625 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5629 GError *gerror = NULL;
5631 mono_error_init (error);
5637 return g_strdup ("");
5639 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5641 mono_error_set_argument (error, "string", "%s", gerror->message);
5642 g_error_free (gerror);
5645 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5646 if (s->length > written) {
5647 /* allocate the total length and copy the part of the string that has been converted */
5648 char *as2 = g_malloc0 (s->length);
5649 memcpy (as2, as, written);
5658 * mono_string_to_utf8_ignore:
5661 * Converts a MonoString to its UTF8 representation. Will ignore
5662 * invalid surrogate pairs.
5663 * The resulting buffer should be freed with mono_free().
5667 mono_string_to_utf8_ignore (MonoString *s)
5676 return g_strdup ("");
5678 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5680 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5681 if (s->length > written) {
5682 /* allocate the total length and copy the part of the string that has been converted */
5683 char *as2 = g_malloc0 (s->length);
5684 memcpy (as2, as, written);
5693 * mono_string_to_utf8_image_ignore:
5694 * @s: a System.String
5696 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5699 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5701 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5705 * mono_string_to_utf8_mp_ignore:
5706 * @s: a System.String
5708 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5711 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5713 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5718 * mono_string_to_utf16:
5721 * Return an null-terminated array of the utf-16 chars
5722 * contained in @s. The result must be freed with g_free().
5723 * This is a temporary helper until our string implementation
5724 * is reworked to always include the null terminating char.
5727 mono_string_to_utf16 (MonoString *s)
5734 as = g_malloc ((s->length * 2) + 2);
5735 as [(s->length * 2)] = '\0';
5736 as [(s->length * 2) + 1] = '\0';
5739 return (gunichar2 *)(as);
5742 memcpy (as, mono_string_chars(s), s->length * 2);
5743 return (gunichar2 *)(as);
5747 * mono_string_to_utf32:
5750 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5751 * contained in @s. The result must be freed with g_free().
5754 mono_string_to_utf32 (MonoString *s)
5756 mono_unichar4 *utf32_output = NULL;
5757 GError *error = NULL;
5758 glong items_written;
5763 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5766 g_error_free (error);
5768 return utf32_output;
5772 * mono_string_from_utf16:
5773 * @data: the UTF16 string (LPWSTR) to convert
5775 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5777 * Returns: a MonoString.
5780 mono_string_from_utf16 (gunichar2 *data)
5782 MonoDomain *domain = mono_domain_get ();
5788 while (data [len]) len++;
5790 return mono_string_new_utf16 (domain, data, len);
5794 * mono_string_from_utf32:
5795 * @data: the UTF32 string (LPWSTR) to convert
5797 * Converts a UTF32 (UCS-4)to a MonoString.
5799 * Returns: a MonoString.
5802 mono_string_from_utf32 (mono_unichar4 *data)
5804 MonoString* result = NULL;
5805 mono_unichar2 *utf16_output = NULL;
5806 GError *error = NULL;
5807 glong items_written;
5813 while (data [len]) len++;
5815 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5818 g_error_free (error);
5820 result = mono_string_from_utf16 (utf16_output);
5821 g_free (utf16_output);
5826 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5833 r = mono_string_to_utf8_ignore (s);
5835 r = mono_string_to_utf8_checked (s, error);
5836 if (!mono_error_ok (error))
5843 len = strlen (r) + 1;
5845 mp_s = mono_mempool_alloc (mp, len);
5847 mp_s = mono_image_alloc (image, len);
5849 memcpy (mp_s, r, len);
5857 * mono_string_to_utf8_image:
5858 * @s: a System.String
5860 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5863 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5865 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5869 * mono_string_to_utf8_mp:
5870 * @s: a System.String
5872 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5875 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5877 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5881 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5884 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5886 eh_callbacks = *cbs;
5889 MonoRuntimeExceptionHandlingCallbacks *
5890 mono_get_eh_callbacks (void)
5892 return &eh_callbacks;
5896 * mono_raise_exception:
5897 * @ex: exception object
5899 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5902 mono_raise_exception (MonoException *ex)
5905 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5906 * that will cause gcc to omit the function epilog, causing problems when
5907 * the JIT tries to walk the stack, since the return address on the stack
5908 * will point into the next function in the executable, not this one.
5910 eh_callbacks.mono_raise_exception (ex);
5914 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5916 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5920 * mono_wait_handle_new:
5921 * @domain: Domain where the object will be created
5922 * @handle: Handle for the wait handle
5924 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5927 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5929 MonoWaitHandle *res;
5930 gpointer params [1];
5931 static MonoMethod *handle_set;
5933 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5935 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5937 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5939 params [0] = &handle;
5940 mono_runtime_invoke (handle_set, res, params, NULL);
5946 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5948 static MonoClassField *f_os_handle;
5949 static MonoClassField *f_safe_handle;
5951 if (!f_os_handle && !f_safe_handle) {
5952 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5953 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5958 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5962 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5969 mono_runtime_capture_context (MonoDomain *domain)
5971 RuntimeInvokeFunction runtime_invoke;
5973 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5974 MonoMethod *method = mono_get_context_capture_method ();
5975 MonoMethod *wrapper;
5978 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5979 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5980 domain->capture_context_method = mono_compile_method (method);
5983 runtime_invoke = domain->capture_context_runtime_invoke;
5985 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5988 * mono_async_result_new:
5989 * @domain:domain where the object will be created.
5990 * @handle: wait handle.
5991 * @state: state to pass to AsyncResult
5992 * @data: C closure data.
5994 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5995 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5999 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6001 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6002 MonoObject *context = mono_runtime_capture_context (domain);
6003 /* we must capture the execution context from the original thread */
6005 MONO_OBJECT_SETREF (res, execution_context, context);
6006 /* note: result may be null if the flow is suppressed */
6010 MONO_OBJECT_SETREF (res, object_data, object_data);
6011 MONO_OBJECT_SETREF (res, async_state, state);
6013 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6015 res->sync_completed = FALSE;
6016 res->completed = FALSE;
6022 mono_message_init (MonoDomain *domain,
6023 MonoMethodMessage *this,
6024 MonoReflectionMethod *method,
6025 MonoArray *out_args)
6027 static MonoClass *object_array_klass;
6028 static MonoClass *byte_array_klass;
6029 static MonoClass *string_array_klass;
6030 MonoMethodSignature *sig = mono_method_signature (method->method);
6036 if (!object_array_klass) {
6039 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6041 byte_array_klass = klass;
6043 klass = mono_array_class_get (mono_defaults.string_class, 1);
6045 string_array_klass = klass;
6047 klass = mono_array_class_get (mono_defaults.object_class, 1);
6050 mono_atomic_store_release (&object_array_klass, klass);
6053 MONO_OBJECT_SETREF (this, method, method);
6055 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6056 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6057 this->async_result = NULL;
6058 this->call_type = CallType_Sync;
6060 names = g_new (char *, sig->param_count);
6061 mono_method_get_param_names (method->method, (const char **) names);
6062 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6064 for (i = 0; i < sig->param_count; i++) {
6065 name = mono_string_new (domain, names [i]);
6066 mono_array_setref (this->names, i, name);
6070 for (i = 0, j = 0; i < sig->param_count; i++) {
6071 if (sig->params [i]->byref) {
6073 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6074 mono_array_setref (this->args, i, arg);
6078 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6082 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6085 mono_array_set (this->arg_types, guint8, i, arg_type);
6089 #ifndef DISABLE_REMOTING
6091 * mono_remoting_invoke:
6092 * @real_proxy: pointer to a RealProxy object
6093 * @msg: The MonoMethodMessage to execute
6094 * @exc: used to store exceptions
6095 * @out_args: used to store output arguments
6097 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6098 * IMessage interface and it is not trivial to extract results from there. So
6099 * we call an helper method PrivateInvoke instead of calling
6100 * RealProxy::Invoke() directly.
6102 * Returns: the result object.
6105 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6106 MonoObject **exc, MonoArray **out_args)
6108 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6111 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6114 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6116 real_proxy->vtable->domain->private_invoke_method = im;
6119 pa [0] = real_proxy;
6124 return mono_runtime_invoke (im, NULL, pa, exc);
6129 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6130 MonoObject **exc, MonoArray **out_args)
6132 static MonoClass *object_array_klass;
6135 MonoMethodSignature *sig;
6137 int i, j, outarg_count = 0;
6139 #ifndef DISABLE_REMOTING
6140 if (target && mono_object_is_transparent_proxy (target)) {
6141 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6142 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6143 target = tp->rp->unwrapped_server;
6145 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6150 domain = mono_domain_get ();
6151 method = msg->method->method;
6152 sig = mono_method_signature (method);
6154 for (i = 0; i < sig->param_count; i++) {
6155 if (sig->params [i]->byref)
6159 if (!object_array_klass) {
6162 klass = mono_array_class_get (mono_defaults.object_class, 1);
6165 mono_memory_barrier ();
6166 object_array_klass = klass;
6169 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6170 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6173 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6175 for (i = 0, j = 0; i < sig->param_count; i++) {
6176 if (sig->params [i]->byref) {
6178 arg = mono_array_get (msg->args, gpointer, i);
6179 mono_array_setref (*out_args, j, arg);
6188 * mono_object_to_string:
6190 * @exc: Any exception thrown by ToString (). May be NULL.
6192 * Returns: the result of calling ToString () on an object.
6195 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6197 static MonoMethod *to_string = NULL;
6204 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6206 method = mono_object_get_virtual_method (obj, to_string);
6208 // Unbox value type if needed
6209 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6210 target = mono_object_unbox (obj);
6213 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6217 * mono_print_unhandled_exception:
6218 * @exc: The exception
6220 * Prints the unhandled exception.
6223 mono_print_unhandled_exception (MonoObject *exc)
6226 char *message = (char*)"";
6227 gboolean free_message = FALSE;
6230 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6231 message = g_strdup ("OutOfMemoryException");
6232 free_message = TRUE;
6235 if (((MonoException*)exc)->native_trace_ips) {
6236 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6237 free_message = TRUE;
6239 MonoObject *other_exc = NULL;
6240 str = mono_object_to_string (exc, &other_exc);
6242 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6243 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6245 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6246 original_backtrace, nested_backtrace);
6248 g_free (original_backtrace);
6249 g_free (nested_backtrace);
6250 free_message = TRUE;
6252 message = mono_string_to_utf8_checked (str, &error);
6253 if (!mono_error_ok (&error)) {
6254 mono_error_cleanup (&error);
6255 message = (char *) "";
6257 free_message = TRUE;
6264 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6265 * exc->vtable->klass->name, message);
6267 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6274 * mono_delegate_ctor:
6275 * @this: pointer to an uninitialized delegate object
6276 * @target: target object
6277 * @addr: pointer to native code
6280 * Initialize a delegate and sets a specific method, not the one
6281 * associated with addr. This is useful when sharing generic code.
6282 * In that case addr will most probably not be associated with the
6283 * correct instantiation of the method.
6286 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6288 MonoDelegate *delegate = (MonoDelegate *)this;
6295 delegate->method = method;
6297 class = this->vtable->klass;
6298 mono_stats.delegate_creations++;
6300 #ifndef DISABLE_REMOTING
6301 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6303 method = mono_marshal_get_remoting_invoke (method);
6304 delegate->method_ptr = mono_compile_method (method);
6305 MONO_OBJECT_SETREF (delegate, target, target);
6309 delegate->method_ptr = addr;
6310 MONO_OBJECT_SETREF (delegate, target, target);
6313 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6317 * mono_delegate_ctor:
6318 * @this: pointer to an uninitialized delegate object
6319 * @target: target object
6320 * @addr: pointer to native code
6322 * This is used to initialize a delegate.
6325 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6327 MonoDomain *domain = mono_domain_get ();
6329 MonoMethod *method = NULL;
6333 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6335 if (!ji && domain != mono_get_root_domain ())
6336 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6338 method = mono_jit_info_get_method (ji);
6339 g_assert (!method->klass->generic_container);
6342 mono_delegate_ctor_with_method (this, target, addr, method);
6346 * mono_method_call_message_new:
6347 * @method: method to encapsulate
6348 * @params: parameters to the method
6349 * @invoke: optional, delegate invoke.
6350 * @cb: async callback delegate.
6351 * @state: state passed to the async callback.
6353 * Translates arguments pointers into a MonoMethodMessage.
6356 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6357 MonoDelegate **cb, MonoObject **state)
6359 MonoDomain *domain = mono_domain_get ();
6360 MonoMethodSignature *sig = mono_method_signature (method);
6361 MonoMethodMessage *msg;
6364 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6367 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6368 count = sig->param_count - 2;
6370 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6371 count = sig->param_count;
6374 for (i = 0; i < count; i++) {
6379 if (sig->params [i]->byref)
6380 vpos = *((gpointer *)params [i]);
6384 type = sig->params [i]->type;
6385 class = mono_class_from_mono_type (sig->params [i]);
6387 if (class->valuetype)
6388 arg = mono_value_box (domain, class, vpos);
6390 arg = *((MonoObject **)vpos);
6392 mono_array_setref (msg->args, i, arg);
6395 if (cb != NULL && state != NULL) {
6396 *cb = *((MonoDelegate **)params [i]);
6398 *state = *((MonoObject **)params [i]);
6405 * mono_method_return_message_restore:
6407 * Restore results from message based processing back to arguments pointers
6410 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6412 MonoMethodSignature *sig = mono_method_signature (method);
6413 int i, j, type, size, out_len;
6415 if (out_args == NULL)
6417 out_len = mono_array_length (out_args);
6421 for (i = 0, j = 0; i < sig->param_count; i++) {
6422 MonoType *pt = sig->params [i];
6427 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6429 arg = mono_array_get (out_args, gpointer, j);
6432 g_assert (type != MONO_TYPE_VOID);
6434 if (MONO_TYPE_IS_REFERENCE (pt)) {
6435 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6438 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6439 size = mono_class_value_size (class, NULL);
6440 if (class->has_references)
6441 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6443 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6445 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6446 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6455 #ifndef DISABLE_REMOTING
6458 * mono_load_remote_field:
6459 * @this: pointer to an object
6460 * @klass: klass of the object containing @field
6461 * @field: the field to load
6462 * @res: a storage to store the result
6464 * This method is called by the runtime on attempts to load fields of
6465 * transparent proxy objects. @this points to such TP, @klass is the class of
6466 * the object containing @field. @res is a storage location which can be
6467 * used to store the result.
6469 * Returns: an address pointing to the value of field.
6472 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6474 static MonoMethod *getter = NULL;
6475 MonoDomain *domain = mono_domain_get ();
6476 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6477 MonoClass *field_class;
6478 MonoMethodMessage *msg;
6479 MonoArray *out_args;
6483 g_assert (mono_object_is_transparent_proxy (this));
6484 g_assert (res != NULL);
6486 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6487 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6492 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6496 field_class = mono_class_from_mono_type (field->type);
6498 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6499 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6500 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6502 full_name = mono_type_get_full_name (klass);
6503 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6504 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6507 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6509 if (exc) mono_raise_exception ((MonoException *)exc);
6511 if (mono_array_length (out_args) == 0)
6514 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6516 if (field_class->valuetype) {
6517 return ((char *)*res) + sizeof (MonoObject);
6523 * mono_load_remote_field_new:
6528 * Missing documentation.
6531 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6533 static MonoMethod *getter = NULL;
6534 MonoDomain *domain = mono_domain_get ();
6535 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6536 MonoClass *field_class;
6537 MonoMethodMessage *msg;
6538 MonoArray *out_args;
6539 MonoObject *exc, *res;
6542 g_assert (mono_object_is_transparent_proxy (this));
6544 field_class = mono_class_from_mono_type (field->type);
6546 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6548 if (field_class->valuetype) {
6549 res = mono_object_new (domain, field_class);
6550 val = ((gchar *) res) + sizeof (MonoObject);
6554 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6559 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6563 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6564 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6566 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6568 full_name = mono_type_get_full_name (klass);
6569 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6570 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6573 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6575 if (exc) mono_raise_exception ((MonoException *)exc);
6577 if (mono_array_length (out_args) == 0)
6580 res = mono_array_get (out_args, MonoObject *, 0);
6586 * mono_store_remote_field:
6587 * @this: pointer to an object
6588 * @klass: klass of the object containing @field
6589 * @field: the field to load
6590 * @val: the value/object to store
6592 * This method is called by the runtime on attempts to store fields of
6593 * transparent proxy objects. @this points to such TP, @klass is the class of
6594 * the object containing @field. @val is the new value to store in @field.
6597 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6599 static MonoMethod *setter = NULL;
6600 MonoDomain *domain = mono_domain_get ();
6601 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6602 MonoClass *field_class;
6603 MonoMethodMessage *msg;
6604 MonoArray *out_args;
6609 g_assert (mono_object_is_transparent_proxy (this));
6611 field_class = mono_class_from_mono_type (field->type);
6613 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6614 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6615 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6620 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6624 if (field_class->valuetype)
6625 arg = mono_value_box (domain, field_class, val);
6627 arg = *((MonoObject **)val);
6630 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6631 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6633 full_name = mono_type_get_full_name (klass);
6634 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6635 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6636 mono_array_setref (msg->args, 2, arg);
6639 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6641 if (exc) mono_raise_exception ((MonoException *)exc);
6645 * mono_store_remote_field_new:
6651 * Missing documentation
6654 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6656 static MonoMethod *setter = NULL;
6657 MonoDomain *domain = mono_domain_get ();
6658 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6659 MonoClass *field_class;
6660 MonoMethodMessage *msg;
6661 MonoArray *out_args;
6665 g_assert (mono_object_is_transparent_proxy (this));
6667 field_class = mono_class_from_mono_type (field->type);
6669 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6670 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6671 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6676 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6680 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6681 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6683 full_name = mono_type_get_full_name (klass);
6684 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6685 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6686 mono_array_setref (msg->args, 2, arg);
6689 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6691 if (exc) mono_raise_exception ((MonoException *)exc);
6696 * mono_create_ftnptr:
6698 * Given a function address, create a function descriptor for it.
6699 * This is only needed on some platforms.
6702 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6704 return callbacks.create_ftnptr (domain, addr);
6708 * mono_get_addr_from_ftnptr:
6710 * Given a pointer to a function descriptor, return the function address.
6711 * This is only needed on some platforms.
6714 mono_get_addr_from_ftnptr (gpointer descr)
6716 return callbacks.get_addr_from_ftnptr (descr);
6720 * mono_string_chars:
6723 * Returns a pointer to the UCS16 characters stored in the MonoString
6726 mono_string_chars (MonoString *s)
6732 * mono_string_length:
6735 * Returns the lenght in characters of the string
6738 mono_string_length (MonoString *s)
6744 * mono_array_length:
6745 * @array: a MonoArray*
6747 * Returns the total number of elements in the array. This works for
6748 * both vectors and multidimensional arrays.
6751 mono_array_length (MonoArray *array)
6753 return array->max_length;
6757 * mono_array_addr_with_size:
6758 * @array: a MonoArray*
6759 * @size: size of the array elements
6760 * @idx: index into the array
6762 * Returns the address of the @idx element in the array.
6765 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6767 return ((char*)(array)->vector) + size * idx;