2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include "cominterop.h"
49 #define NEED_TO_ZERO_PTRFREE 1
50 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
51 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
52 #ifdef HAVE_GC_GCJ_MALLOC
53 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
61 #define GC_NO_DESCRIPTOR (NULL)
62 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
64 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
66 #define NEED_TO_ZERO_PTRFREE 1
67 #define GC_NO_DESCRIPTOR (NULL)
68 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
69 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
70 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
84 free_main_args (void);
87 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
90 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
91 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
92 static mono_mutex_t ldstr_section;
94 static gboolean profile_allocs = TRUE;
97 mono_runtime_object_init (MonoObject *this)
99 MonoMethod *method = NULL;
100 MonoClass *klass = this->vtable->klass;
102 method = mono_class_get_method_from_name (klass, ".ctor", 0);
104 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
106 if (method->klass->valuetype)
107 this = mono_object_unbox (this);
108 mono_runtime_invoke (method, this, NULL, NULL);
111 /* The pseudo algorithm for type initialization from the spec
112 Note it doesn't say anything about domains - only threads.
114 2. If the type is initialized you are done.
115 2.1. If the type is not yet initialized, try to take an
117 2.2. If successful, record this thread as responsible for
118 initializing the type and proceed to step 2.3.
119 2.2.1. If not, see whether this thread or any thread
120 waiting for this thread to complete already holds the lock.
121 2.2.2. If so, return since blocking would create a deadlock. This thread
122 will now see an incompletely initialized state for the type,
123 but no deadlock will arise.
124 2.2.3 If not, block until the type is initialized then return.
125 2.3 Initialize the parent type and then all interfaces implemented
127 2.4 Execute the type initialization code for this type.
128 2.5 Mark the type as initialized, release the initialization lock,
129 awaken any threads waiting for this type to be initialized,
136 guint32 initializing_tid;
137 guint32 waiting_count;
139 mono_mutex_t initialization_section;
140 } TypeInitializationLock;
142 /* for locking access to type_initialization_hash and blocked_thread_hash */
143 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
144 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
145 static mono_mutex_t type_initialization_section;
147 /* from vtable to lock */
148 static GHashTable *type_initialization_hash;
150 /* from thread id to thread id being waited on */
151 static GHashTable *blocked_thread_hash;
154 static MonoThread *main_thread;
156 /* Functions supplied by the runtime */
157 static MonoRuntimeCallbacks callbacks;
160 * mono_thread_set_main:
161 * @thread: thread to set as the main thread
163 * This function can be used to instruct the runtime to treat @thread
164 * as the main thread, ie, the thread that would normally execute the Main()
165 * method. This basically means that at the end of @thread, the runtime will
166 * wait for the existing foreground threads to quit and other such details.
169 mono_thread_set_main (MonoThread *thread)
171 static gboolean registered = FALSE;
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
178 main_thread = thread;
182 mono_thread_get_main (void)
188 mono_type_initialization_init (void)
190 mono_mutex_init_recursive (&type_initialization_section);
191 type_initialization_hash = g_hash_table_new (NULL, NULL);
192 blocked_thread_hash = g_hash_table_new (NULL, NULL);
193 mono_mutex_init_recursive (&ldstr_section);
197 mono_type_initialization_cleanup (void)
200 /* This is causing race conditions with
201 * mono_release_type_locks
203 mono_mutex_destroy (&type_initialization_section);
204 g_hash_table_destroy (type_initialization_hash);
205 type_initialization_hash = NULL;
207 mono_mutex_destroy (&ldstr_section);
208 g_hash_table_destroy (blocked_thread_hash);
209 blocked_thread_hash = NULL;
215 * get_type_init_exception_for_vtable:
217 * Return the stored type initialization exception for VTABLE.
219 static MonoException*
220 get_type_init_exception_for_vtable (MonoVTable *vtable)
222 MonoDomain *domain = vtable->domain;
223 MonoClass *klass = vtable->klass;
227 if (!vtable->init_failed)
228 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
231 * If the initializing thread was rudely aborted, the exception is not stored
235 mono_domain_lock (domain);
236 if (domain->type_init_exception_hash)
237 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
238 mono_domain_unlock (domain);
241 if (klass->name_space && *klass->name_space)
242 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
244 full_name = g_strdup (klass->name);
245 ex = mono_get_exception_type_initialization (full_name, NULL);
252 * mono_runtime_class_init:
253 * @vtable: vtable that needs to be initialized
255 * This routine calls the class constructor for @vtable.
258 mono_runtime_class_init (MonoVTable *vtable)
260 mono_runtime_class_init_full (vtable, TRUE);
264 * mono_runtime_class_init_full:
265 * @vtable that neeeds to be initialized
266 * @raise_exception is TRUE, exceptions are raised intead of returned
270 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
273 MonoException *exc_to_throw;
274 MonoMethod *method = NULL;
280 if (vtable->initialized)
284 klass = vtable->klass;
286 if (!klass->image->checked_module_cctor) {
287 mono_image_check_for_module_cctor (klass->image);
288 if (klass->image->has_module_cctor) {
290 MonoClass *module_klass;
291 MonoVTable *module_vtable;
293 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
295 exc = mono_error_convert_to_exception (&error);
297 mono_raise_exception (exc);
301 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
304 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
309 method = mono_class_get_cctor (klass);
312 MonoDomain *domain = vtable->domain;
313 TypeInitializationLock *lock;
314 guint32 tid = GetCurrentThreadId();
315 int do_initialization = 0;
316 MonoDomain *last_domain = NULL;
318 mono_type_initialization_lock ();
319 /* double check... */
320 if (vtable->initialized) {
321 mono_type_initialization_unlock ();
324 if (vtable->init_failed) {
325 mono_type_initialization_unlock ();
327 /* The type initialization already failed once, rethrow the same exception */
329 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
330 return get_type_init_exception_for_vtable (vtable);
332 lock = g_hash_table_lookup (type_initialization_hash, vtable);
334 /* This thread will get to do the initialization */
335 if (mono_domain_get () != domain) {
336 /* Transfer into the target domain */
337 last_domain = mono_domain_get ();
338 if (!mono_domain_set (domain, FALSE)) {
339 vtable->initialized = 1;
340 mono_type_initialization_unlock ();
342 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
343 return mono_get_exception_appdomain_unloaded ();
346 lock = g_malloc (sizeof(TypeInitializationLock));
347 mono_mutex_init_recursive (&lock->initialization_section);
348 lock->initializing_tid = tid;
349 lock->waiting_count = 1;
351 /* grab the vtable lock while this thread still owns type_initialization_section */
352 mono_mutex_lock (&lock->initialization_section);
353 g_hash_table_insert (type_initialization_hash, vtable, lock);
354 do_initialization = 1;
357 TypeInitializationLock *pending_lock;
359 if (lock->initializing_tid == tid || lock->done) {
360 mono_type_initialization_unlock ();
363 /* see if the thread doing the initialization is already blocked on this thread */
364 blocked = GUINT_TO_POINTER (lock->initializing_tid);
365 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
366 if (pending_lock->initializing_tid == tid) {
367 if (!pending_lock->done) {
368 mono_type_initialization_unlock ();
371 /* the thread doing the initialization is blocked on this thread,
372 but on a lock that has already been freed. It just hasn't got
377 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
379 ++lock->waiting_count;
380 /* record the fact that we are waiting on the initializing thread */
381 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
383 mono_type_initialization_unlock ();
385 if (do_initialization) {
386 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
388 /* If the initialization failed, mark the class as unusable. */
389 /* Avoid infinite loops */
391 (klass->image == mono_defaults.corlib &&
392 !strcmp (klass->name_space, "System") &&
393 !strcmp (klass->name, "TypeInitializationException")))) {
394 vtable->init_failed = 1;
396 if (klass->name_space && *klass->name_space)
397 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
399 full_name = g_strdup (klass->name);
400 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
404 * Store the exception object so it could be thrown on subsequent
407 mono_domain_lock (domain);
408 if (!domain->type_init_exception_hash)
409 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
410 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
411 mono_domain_unlock (domain);
415 mono_domain_set (last_domain, TRUE);
417 mono_mutex_unlock (&lock->initialization_section);
419 /* this just blocks until the initializing thread is done */
420 mono_mutex_lock (&lock->initialization_section);
421 mono_mutex_unlock (&lock->initialization_section);
424 mono_type_initialization_lock ();
425 if (lock->initializing_tid != tid)
426 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
427 --lock->waiting_count;
428 if (lock->waiting_count == 0) {
429 mono_mutex_destroy (&lock->initialization_section);
430 g_hash_table_remove (type_initialization_hash, vtable);
433 mono_memory_barrier ();
434 if (!vtable->init_failed)
435 vtable->initialized = 1;
436 mono_type_initialization_unlock ();
438 if (vtable->init_failed) {
439 /* Either we were the initializing thread or we waited for the initialization */
441 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
442 return get_type_init_exception_for_vtable (vtable);
445 vtable->initialized = 1;
452 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
454 MonoVTable *vtable = (MonoVTable*)key;
456 TypeInitializationLock *lock = (TypeInitializationLock*) value;
457 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
460 * Have to set this since it cannot be set by the normal code in
461 * mono_runtime_class_init (). In this case, the exception object is not stored,
462 * and get_type_init_exception_for_class () needs to be aware of this.
464 vtable->init_failed = 1;
465 mono_mutex_unlock (&lock->initialization_section);
466 --lock->waiting_count;
467 if (lock->waiting_count == 0) {
468 mono_mutex_destroy (&lock->initialization_section);
477 mono_release_type_locks (MonoInternalThread *thread)
479 mono_type_initialization_lock ();
480 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
481 mono_type_initialization_unlock ();
485 default_trampoline (MonoMethod *method)
491 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
493 g_assert_not_reached ();
498 #ifndef DISABLE_REMOTING
501 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
503 g_error ("remoting not installed");
507 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
511 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
513 g_assert_not_reached ();
517 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
518 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
519 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
520 static MonoImtThunkBuilder imt_thunk_builder = NULL;
521 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
522 #if (MONO_IMT_SIZE > 32)
523 #error "MONO_IMT_SIZE cannot be larger than 32"
527 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
529 memcpy (&callbacks, cbs, sizeof (*cbs));
532 MonoRuntimeCallbacks*
533 mono_get_runtime_callbacks (void)
539 mono_install_trampoline (MonoTrampoline func)
541 arch_create_jit_trampoline = func? func: default_trampoline;
545 mono_install_jump_trampoline (MonoJumpTrampoline func)
547 arch_create_jump_trampoline = func? func: default_jump_trampoline;
550 #ifndef DISABLE_REMOTING
552 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
554 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
559 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
561 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
565 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
566 imt_thunk_builder = func;
569 static MonoCompileFunc default_mono_compile_method = NULL;
572 * mono_install_compile_method:
573 * @func: function to install
575 * This is a VM internal routine
578 mono_install_compile_method (MonoCompileFunc func)
580 default_mono_compile_method = func;
584 * mono_compile_method:
585 * @method: The method to compile.
587 * This JIT-compiles the method, and returns the pointer to the native code
591 mono_compile_method (MonoMethod *method)
593 if (!default_mono_compile_method) {
594 g_error ("compile method called on uninitialized runtime");
597 return default_mono_compile_method (method);
601 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
603 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
607 mono_runtime_create_delegate_trampoline (MonoClass *klass)
609 return arch_create_delegate_trampoline (mono_domain_get (), klass);
612 static MonoFreeMethodFunc default_mono_free_method = NULL;
615 * mono_install_free_method:
616 * @func: pointer to the MonoFreeMethodFunc used to release a method
618 * This is an internal VM routine, it is used for the engines to
619 * register a handler to release the resources associated with a method.
621 * Methods are freed when no more references to the delegate that holds
625 mono_install_free_method (MonoFreeMethodFunc func)
627 default_mono_free_method = func;
631 * mono_runtime_free_method:
632 * @domain; domain where the method is hosted
633 * @method: method to release
635 * This routine is invoked to free the resources associated with
636 * a method that has been JIT compiled. This is used to discard
637 * methods that were used only temporarily (for example, used in marshalling)
641 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
643 if (default_mono_free_method != NULL)
644 default_mono_free_method (domain, method);
646 mono_method_clear_object (domain, method);
648 mono_free_method (method);
652 * The vtables in the root appdomain are assumed to be reachable by other
653 * roots, and we don't use typed allocation in the other domains.
656 /* The sync block is no longer a GC pointer */
657 #define GC_HEADER_BITMAP (0)
659 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
662 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
664 MonoClassField *field;
670 max_size = mono_class_data_size (class) / sizeof (gpointer);
672 max_size = class->instance_size / sizeof (gpointer);
673 if (max_size > size) {
674 g_assert (offset <= 0);
675 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
680 /*An Ephemeron cannot be marked by sgen*/
681 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
683 memset (bitmap, 0, size / 8);
688 for (p = class; p != NULL; p = p->parent) {
689 gpointer iter = NULL;
690 while ((field = mono_class_get_fields (p, &iter))) {
694 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
696 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
699 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
702 /* FIXME: should not happen, flag as type load error */
703 if (field->type->byref)
706 if (static_fields && field->offset == -1)
710 pos = field->offset / sizeof (gpointer);
713 type = mono_type_get_underlying_type (field->type);
714 switch (type->type) {
717 case MONO_TYPE_FNPTR:
719 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
724 if (class->image != mono_defaults.corlib)
727 case MONO_TYPE_STRING:
728 case MONO_TYPE_SZARRAY:
729 case MONO_TYPE_CLASS:
730 case MONO_TYPE_OBJECT:
731 case MONO_TYPE_ARRAY:
732 g_assert ((field->offset % sizeof(gpointer)) == 0);
734 g_assert (pos < size || pos <= max_size);
735 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
736 *max_set = MAX (*max_set, pos);
738 case MONO_TYPE_GENERICINST:
739 if (!mono_type_generic_inst_is_valuetype (type)) {
740 g_assert ((field->offset % sizeof(gpointer)) == 0);
742 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
743 *max_set = MAX (*max_set, pos);
748 case MONO_TYPE_VALUETYPE: {
749 MonoClass *fclass = mono_class_from_mono_type (field->type);
750 if (fclass->has_references) {
751 /* remove the object header */
752 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
766 case MONO_TYPE_BOOLEAN:
770 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
781 * mono_class_compute_bitmap:
783 * Mono internal function to compute a bitmap of reference fields in a class.
786 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
788 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
793 * similar to the above, but sets the bits in the bitmap for any non-ref field
794 * and ignores static fields
797 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
799 MonoClassField *field;
804 max_size = class->instance_size / sizeof (gpointer);
805 if (max_size >= size) {
806 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
809 for (p = class; p != NULL; p = p->parent) {
810 gpointer iter = NULL;
811 while ((field = mono_class_get_fields (p, &iter))) {
814 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
816 /* FIXME: should not happen, flag as type load error */
817 if (field->type->byref)
820 pos = field->offset / sizeof (gpointer);
823 type = mono_type_get_underlying_type (field->type);
824 switch (type->type) {
825 #if SIZEOF_VOID_P == 8
829 case MONO_TYPE_FNPTR:
834 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
835 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
836 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
839 #if SIZEOF_VOID_P == 4
843 case MONO_TYPE_FNPTR:
848 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
849 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
850 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
856 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
857 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
858 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
861 case MONO_TYPE_BOOLEAN:
864 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
866 case MONO_TYPE_STRING:
867 case MONO_TYPE_SZARRAY:
868 case MONO_TYPE_CLASS:
869 case MONO_TYPE_OBJECT:
870 case MONO_TYPE_ARRAY:
872 case MONO_TYPE_GENERICINST:
873 if (!mono_type_generic_inst_is_valuetype (type)) {
878 case MONO_TYPE_VALUETYPE: {
879 MonoClass *fclass = mono_class_from_mono_type (field->type);
880 /* remove the object header */
881 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
885 g_assert_not_reached ();
894 * mono_class_insecure_overlapping:
895 * check if a class with explicit layout has references and non-references
896 * fields overlapping.
898 * Returns: TRUE if it is insecure to load the type.
901 mono_class_insecure_overlapping (MonoClass *klass)
905 gsize default_bitmap [4] = {0};
907 gsize default_nrbitmap [4] = {0};
908 int i, insecure = FALSE;
911 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
912 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
914 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
915 int idx = i % (sizeof (bitmap [0]) * 8);
916 if (bitmap [idx] & nrbitmap [idx]) {
921 if (bitmap != default_bitmap)
923 if (nrbitmap != default_nrbitmap)
926 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
934 mono_string_alloc (int length)
936 return mono_string_new_size (mono_domain_get (), length);
940 mono_class_compute_gc_descriptor (MonoClass *class)
944 gsize default_bitmap [4] = {0};
945 static gboolean gcj_inited = FALSE;
950 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
951 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
952 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
953 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
955 #ifdef HAVE_GC_GCJ_MALLOC
957 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
961 #ifdef GC_REDIRECT_TO_LOCAL
962 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
963 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
965 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
966 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
971 mono_loader_unlock ();
975 mono_class_init (class);
977 if (class->gc_descr_inited)
980 class->gc_descr_inited = TRUE;
981 class->gc_descr = GC_NO_DESCRIPTOR;
983 bitmap = default_bitmap;
984 if (class == mono_defaults.string_class) {
985 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
986 } else if (class->rank) {
987 mono_class_compute_gc_descriptor (class->element_class);
988 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
990 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
991 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
992 class->name_space, class->name);*/
994 /* remove the object header */
995 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
996 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));
997 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
998 class->name_space, class->name);*/
999 if (bitmap != default_bitmap)
1003 /*static int count = 0;
1006 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1007 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
1009 if (class->gc_descr == GC_NO_DESCRIPTOR)
1010 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1012 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1013 if (bitmap != default_bitmap)
1019 * field_is_special_static:
1020 * @fklass: The MonoClass to look up.
1021 * @field: The MonoClassField describing the field.
1023 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1024 * SPECIAL_STATIC_NONE otherwise.
1027 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1029 MonoCustomAttrInfo *ainfo;
1031 ainfo = mono_custom_attrs_from_field (fklass, field);
1034 for (i = 0; i < ainfo->num_attrs; ++i) {
1035 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1036 if (klass->image == mono_defaults.corlib) {
1037 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1038 mono_custom_attrs_free (ainfo);
1039 return SPECIAL_STATIC_THREAD;
1041 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1042 mono_custom_attrs_free (ainfo);
1043 return SPECIAL_STATIC_CONTEXT;
1047 mono_custom_attrs_free (ainfo);
1048 return SPECIAL_STATIC_NONE;
1051 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1052 #define mix(a,b,c) { \
1053 a -= c; a ^= rot(c, 4); c += b; \
1054 b -= a; b ^= rot(a, 6); a += c; \
1055 c -= b; c ^= rot(b, 8); b += a; \
1056 a -= c; a ^= rot(c,16); c += b; \
1057 b -= a; b ^= rot(a,19); a += c; \
1058 c -= b; c ^= rot(b, 4); b += a; \
1060 #define final(a,b,c) { \
1061 c ^= b; c -= rot(b,14); \
1062 a ^= c; a -= rot(c,11); \
1063 b ^= a; b -= rot(a,25); \
1064 c ^= b; c -= rot(b,16); \
1065 a ^= c; a -= rot(c,4); \
1066 b ^= a; b -= rot(a,14); \
1067 c ^= b; c -= rot(b,24); \
1071 * mono_method_get_imt_slot:
1073 * The IMT slot is embedded into AOTed code, so this must return the same value
1074 * for the same method across all executions. This means:
1075 * - pointers shouldn't be used as hash values.
1076 * - mono_metadata_str_hash () should be used for hashing strings.
1079 mono_method_get_imt_slot (MonoMethod *method)
1081 MonoMethodSignature *sig;
1083 guint32 *hashes_start, *hashes;
1087 /* This can be used to stress tests the collision code */
1091 * We do this to simplify generic sharing. It will hurt
1092 * performance in cases where a class implements two different
1093 * instantiations of the same generic interface.
1094 * The code in build_imt_slots () depends on this.
1096 if (method->is_inflated)
1097 method = ((MonoMethodInflated*)method)->declaring;
1099 sig = mono_method_signature (method);
1100 hashes_count = sig->param_count + 4;
1101 hashes_start = malloc (hashes_count * sizeof (guint32));
1102 hashes = hashes_start;
1104 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1105 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1106 method->klass->name_space, method->klass->name, method->name);
1109 /* Initialize hashes */
1110 hashes [0] = mono_metadata_str_hash (method->klass->name);
1111 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1112 hashes [2] = mono_metadata_str_hash (method->name);
1113 hashes [3] = mono_metadata_type_hash (sig->ret);
1114 for (i = 0; i < sig->param_count; i++) {
1115 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1118 /* Setup internal state */
1119 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1121 /* Handle most of the hashes */
1122 while (hashes_count > 3) {
1131 /* Handle the last 3 hashes (all the case statements fall through) */
1132 switch (hashes_count) {
1133 case 3 : c += hashes [2];
1134 case 2 : b += hashes [1];
1135 case 1 : a += hashes [0];
1137 case 0: /* nothing left to add */
1141 free (hashes_start);
1142 /* Report the result */
1143 return c % MONO_IMT_SIZE;
1152 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1153 guint32 imt_slot = mono_method_get_imt_slot (method);
1154 MonoImtBuilderEntry *entry;
1156 if (slot_num >= 0 && imt_slot != slot_num) {
1157 /* we build just a single imt slot and this is not it */
1161 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1162 entry->key = method;
1163 entry->value.vtable_slot = vtable_slot;
1164 entry->next = imt_builder [imt_slot];
1165 if (imt_builder [imt_slot] != NULL) {
1166 entry->children = imt_builder [imt_slot]->children + 1;
1167 if (entry->children == 1) {
1168 mono_stats.imt_slots_with_collisions++;
1169 *imt_collisions_bitmap |= (1 << imt_slot);
1172 entry->children = 0;
1173 mono_stats.imt_used_slots++;
1175 imt_builder [imt_slot] = entry;
1178 char *method_name = mono_method_full_name (method, TRUE);
1179 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1180 method, method_name, imt_slot, vtable_slot, entry->children);
1181 g_free (method_name);
1188 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1190 MonoMethod *method = e->key;
1191 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1195 method->klass->name_space,
1196 method->klass->name,
1199 printf (" * %s: NULL\n", message);
1205 compare_imt_builder_entries (const void *p1, const void *p2) {
1206 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1207 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1209 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1213 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1215 int count = end - start;
1216 int chunk_start = out_array->len;
1219 for (i = start; i < end; ++i) {
1220 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1221 item->key = sorted_array [i]->key;
1222 item->value = sorted_array [i]->value;
1223 item->has_target_code = sorted_array [i]->has_target_code;
1224 item->is_equals = TRUE;
1226 item->check_target_idx = out_array->len + 1;
1228 item->check_target_idx = 0;
1229 g_ptr_array_add (out_array, item);
1232 int middle = start + count / 2;
1233 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1235 item->key = sorted_array [middle]->key;
1236 item->is_equals = FALSE;
1237 g_ptr_array_add (out_array, item);
1238 imt_emit_ir (sorted_array, start, middle, out_array);
1239 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1245 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1246 int number_of_entries = entries->children + 1;
1247 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1248 GPtrArray *result = g_ptr_array_new ();
1249 MonoImtBuilderEntry *current_entry;
1252 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1253 sorted_array [i] = current_entry;
1255 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1257 /*for (i = 0; i < number_of_entries; i++) {
1258 print_imt_entry (" sorted array:", sorted_array [i], i);
1261 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1263 free (sorted_array);
1268 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1270 if (imt_builder_entry != NULL) {
1271 if (imt_builder_entry->children == 0 && !fail_tramp) {
1272 /* No collision, return the vtable slot contents */
1273 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1275 /* Collision, build the thunk */
1276 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1279 result = imt_thunk_builder (vtable, domain,
1280 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1281 for (i = 0; i < imt_ir->len; ++i)
1282 g_free (g_ptr_array_index (imt_ir, i));
1283 g_ptr_array_free (imt_ir, TRUE);
1295 static MonoImtBuilderEntry*
1296 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1299 * LOCKING: requires the loader and domain locks.
1303 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1307 guint32 imt_collisions_bitmap = 0;
1308 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1309 int method_count = 0;
1310 gboolean record_method_count_for_max_collisions = FALSE;
1311 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1314 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1316 for (i = 0; i < klass->interface_offsets_count; ++i) {
1317 MonoClass *iface = klass->interfaces_packed [i];
1318 int interface_offset = klass->interface_offsets_packed [i];
1319 int method_slot_in_interface, vt_slot;
1321 if (mono_class_has_variant_generic_params (iface))
1322 has_variant_iface = TRUE;
1324 mono_class_setup_methods (iface);
1325 vt_slot = interface_offset;
1326 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1329 if (slot_num >= 0 && iface->is_inflated) {
1331 * The imt slot of the method is the same as for its declaring method,
1332 * see the comment in mono_method_get_imt_slot (), so we can
1333 * avoid inflating methods which will be discarded by
1334 * add_imt_builder_entry anyway.
1336 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1337 if (mono_method_get_imt_slot (method) != slot_num) {
1342 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1343 if (method->is_generic) {
1344 has_generic_virtual = TRUE;
1349 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1350 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1355 if (extra_interfaces) {
1356 int interface_offset = klass->vtable_size;
1358 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1359 MonoClass* iface = list_item->data;
1360 int method_slot_in_interface;
1361 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1362 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1364 if (method->is_generic)
1365 has_generic_virtual = TRUE;
1366 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1368 interface_offset += iface->method.count;
1371 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1372 /* overwrite the imt slot only if we're building all the entries or if
1373 * we're building this specific one
1375 if (slot_num < 0 || i == slot_num) {
1376 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1379 if (imt_builder [i]) {
1380 MonoImtBuilderEntry *entry;
1382 /* Link entries with imt_builder [i] */
1383 for (entry = entries; entry->next; entry = entry->next) {
1385 MonoMethod *method = (MonoMethod*)entry->key;
1386 char *method_name = mono_method_full_name (method, TRUE);
1387 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1388 g_free (method_name);
1391 entry->next = imt_builder [i];
1392 entries->children += imt_builder [i]->children + 1;
1394 imt_builder [i] = entries;
1397 if (has_generic_virtual || has_variant_iface) {
1399 * There might be collisions later when the the thunk is expanded.
1401 imt_collisions_bitmap |= (1 << i);
1404 * The IMT thunk might be called with an instance of one of the
1405 * generic virtual methods, so has to fallback to the IMT trampoline.
1407 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1409 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1412 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1416 if (imt_builder [i] != NULL) {
1417 int methods_in_slot = imt_builder [i]->children + 1;
1418 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1419 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1420 record_method_count_for_max_collisions = TRUE;
1422 method_count += methods_in_slot;
1426 mono_stats.imt_number_of_methods += method_count;
1427 if (record_method_count_for_max_collisions) {
1428 mono_stats.imt_method_count_when_max_collisions = method_count;
1431 for (i = 0; i < MONO_IMT_SIZE; i++) {
1432 MonoImtBuilderEntry* entry = imt_builder [i];
1433 while (entry != NULL) {
1434 MonoImtBuilderEntry* next = entry->next;
1440 /* we OR the bitmap since we may build just a single imt slot at a time */
1441 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1445 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1446 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1450 * mono_vtable_build_imt_slot:
1451 * @vtable: virtual object table struct
1452 * @imt_slot: slot in the IMT table
1454 * Fill the given @imt_slot in the IMT table of @vtable with
1455 * a trampoline or a thunk for the case of collisions.
1456 * This is part of the internal mono API.
1458 * LOCKING: Take the domain lock.
1461 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1463 gpointer *imt = (gpointer*)vtable;
1464 imt -= MONO_IMT_SIZE;
1465 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1467 /* no support for extra interfaces: the proxy objects will need
1468 * to build the complete IMT
1469 * Update and heck needs to ahppen inside the proper domain lock, as all
1470 * the changes made to a MonoVTable.
1472 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1473 mono_domain_lock (vtable->domain);
1474 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1475 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1476 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1477 mono_domain_unlock (vtable->domain);
1478 mono_loader_unlock ();
1483 * The first two free list entries both belong to the wait list: The
1484 * first entry is the pointer to the head of the list and the second
1485 * entry points to the last element. That way appending and removing
1486 * the first element are both O(1) operations.
1488 #ifdef MONO_SMALL_CONFIG
1489 #define NUM_FREE_LISTS 6
1491 #define NUM_FREE_LISTS 12
1493 #define FIRST_FREE_LIST_SIZE 64
1494 #define MAX_WAIT_LENGTH 50
1495 #define THUNK_THRESHOLD 10
1498 * LOCKING: The domain lock must be held.
1501 init_thunk_free_lists (MonoDomain *domain)
1503 if (domain->thunk_free_lists)
1505 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1509 list_index_for_size (int item_size)
1512 int size = FIRST_FREE_LIST_SIZE;
1514 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1523 * mono_method_alloc_generic_virtual_thunk:
1525 * @size: size in bytes
1527 * Allocs size bytes to be used for the code of a generic virtual
1528 * thunk. It's either allocated from the domain's code manager or
1529 * reused from a previously invalidated piece.
1531 * LOCKING: The domain lock must be held.
1534 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1536 static gboolean inited = FALSE;
1537 static int generic_virtual_thunks_size = 0;
1541 MonoThunkFreeList **l;
1543 init_thunk_free_lists (domain);
1545 size += sizeof (guint32);
1546 if (size < sizeof (MonoThunkFreeList))
1547 size = sizeof (MonoThunkFreeList);
1549 i = list_index_for_size (size);
1550 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1551 if ((*l)->size >= size) {
1552 MonoThunkFreeList *item = *l;
1554 return ((guint32*)item) + 1;
1558 /* no suitable item found - search lists of larger sizes */
1559 while (++i < NUM_FREE_LISTS) {
1560 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1563 g_assert (item->size > size);
1564 domain->thunk_free_lists [i] = item->next;
1565 return ((guint32*)item) + 1;
1568 /* still nothing found - allocate it */
1570 mono_counters_register ("Generic virtual thunk bytes",
1571 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1574 generic_virtual_thunks_size += size;
1576 p = mono_domain_code_reserve (domain, size);
1579 mono_domain_lock (domain);
1580 if (!domain->generic_virtual_thunks)
1581 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1582 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1583 mono_domain_unlock (domain);
1589 * LOCKING: The domain lock must be held.
1592 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1595 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1596 gboolean found = FALSE;
1598 mono_domain_lock (domain);
1599 if (!domain->generic_virtual_thunks)
1600 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1601 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1603 mono_domain_unlock (domain);
1606 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1608 init_thunk_free_lists (domain);
1610 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1611 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1612 int length = item->length;
1615 /* unlink the first item from the wait list */
1616 domain->thunk_free_lists [0] = item->next;
1617 domain->thunk_free_lists [0]->length = length - 1;
1619 i = list_index_for_size (item->size);
1621 /* put it in the free list */
1622 item->next = domain->thunk_free_lists [i];
1623 domain->thunk_free_lists [i] = item;
1627 if (domain->thunk_free_lists [1]) {
1628 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1629 domain->thunk_free_lists [0]->length++;
1631 g_assert (!domain->thunk_free_lists [0]);
1633 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1634 domain->thunk_free_lists [0]->length = 1;
1638 typedef struct _GenericVirtualCase {
1642 struct _GenericVirtualCase *next;
1643 } GenericVirtualCase;
1646 * get_generic_virtual_entries:
1648 * Return IMT entries for the generic virtual method instances and
1649 * variant interface methods for vtable slot
1652 static MonoImtBuilderEntry*
1653 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1655 GenericVirtualCase *list;
1656 MonoImtBuilderEntry *entries;
1658 mono_domain_lock (domain);
1659 if (!domain->generic_virtual_cases)
1660 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1662 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1665 for (; list; list = list->next) {
1666 MonoImtBuilderEntry *entry;
1668 if (list->count < THUNK_THRESHOLD)
1671 entry = g_new0 (MonoImtBuilderEntry, 1);
1672 entry->key = list->method;
1673 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1674 entry->has_target_code = 1;
1676 entry->children = entries->children + 1;
1677 entry->next = entries;
1681 mono_domain_unlock (domain);
1683 /* FIXME: Leaking memory ? */
1688 * mono_method_add_generic_virtual_invocation:
1690 * @vtable_slot: pointer to the vtable slot
1691 * @method: the inflated generic virtual method
1692 * @code: the method's code
1694 * Registers a call via unmanaged code to a generic virtual method
1695 * instantiation or variant interface method. If the number of calls reaches a threshold
1696 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1697 * virtual method thunk.
1700 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1701 gpointer *vtable_slot,
1702 MonoMethod *method, gpointer code)
1704 static gboolean inited = FALSE;
1705 static int num_added = 0;
1707 GenericVirtualCase *gvc, *list;
1708 MonoImtBuilderEntry *entries;
1712 mono_domain_lock (domain);
1713 if (!domain->generic_virtual_cases)
1714 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1716 /* Check whether the case was already added */
1717 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1720 if (gvc->method == method)
1725 /* If not found, make a new one */
1727 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1728 gvc->method = method;
1731 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1733 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1736 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1742 if (++gvc->count == THUNK_THRESHOLD) {
1743 gpointer *old_thunk = *vtable_slot;
1744 gpointer vtable_trampoline = NULL;
1745 gpointer imt_trampoline = NULL;
1747 if ((gpointer)vtable_slot < (gpointer)vtable) {
1748 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1749 int imt_slot = MONO_IMT_SIZE + displacement;
1751 /* Force the rebuild of the thunk at the next call */
1752 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1753 *vtable_slot = imt_trampoline;
1755 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1757 entries = get_generic_virtual_entries (domain, vtable_slot);
1759 sorted = imt_sort_slot_entries (entries);
1761 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1765 MonoImtBuilderEntry *next = entries->next;
1770 for (i = 0; i < sorted->len; ++i)
1771 g_free (g_ptr_array_index (sorted, i));
1772 g_ptr_array_free (sorted, TRUE);
1775 #ifndef __native_client__
1776 /* We don't re-use any thunks as there is a lot of overhead */
1777 /* to deleting and re-using code in Native Client. */
1778 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1779 invalidate_generic_virtual_thunk (domain, old_thunk);
1783 mono_domain_unlock (domain);
1786 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1789 * mono_class_vtable:
1790 * @domain: the application domain
1791 * @class: the class to initialize
1793 * VTables are domain specific because we create domain specific code, and
1794 * they contain the domain specific static class data.
1795 * On failure, NULL is returned, and class->exception_type is set.
1798 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1800 return mono_class_vtable_full (domain, class, FALSE);
1804 * mono_class_vtable_full:
1805 * @domain: the application domain
1806 * @class: the class to initialize
1807 * @raise_on_error if an exception should be raised on failure or not
1809 * VTables are domain specific because we create domain specific code, and
1810 * they contain the domain specific static class data.
1813 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1815 MonoClassRuntimeInfo *runtime_info;
1819 if (class->exception_type) {
1821 mono_raise_exception (mono_class_get_exception_for_failure (class));
1825 /* this check can be inlined in jitted code, too */
1826 runtime_info = class->runtime_info;
1827 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1828 return runtime_info->domain_vtables [domain->domain_id];
1829 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1833 * mono_class_try_get_vtable:
1834 * @domain: the application domain
1835 * @class: the class to initialize
1837 * This function tries to get the associated vtable from @class if
1838 * it was already created.
1841 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1843 MonoClassRuntimeInfo *runtime_info;
1847 runtime_info = class->runtime_info;
1848 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1849 return runtime_info->domain_vtables [domain->domain_id];
1854 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1856 size_t alloc_offset;
1859 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1860 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1861 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1863 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1864 g_assert ((imt_table_bytes & 7) == 4);
1871 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1875 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1878 MonoClassRuntimeInfo *runtime_info, *old_info;
1879 MonoClassField *field;
1881 int i, vtable_slots;
1882 size_t imt_table_bytes;
1884 guint32 vtable_size, class_size;
1887 gpointer *interface_offsets;
1889 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1890 mono_domain_lock (domain);
1891 runtime_info = class->runtime_info;
1892 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1893 mono_domain_unlock (domain);
1894 mono_loader_unlock ();
1895 return runtime_info->domain_vtables [domain->domain_id];
1897 if (!class->inited || class->exception_type) {
1898 if (!mono_class_init (class) || class->exception_type) {
1899 mono_domain_unlock (domain);
1900 mono_loader_unlock ();
1902 mono_raise_exception (mono_class_get_exception_for_failure (class));
1907 /* Array types require that their element type be valid*/
1908 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1909 MonoClass *element_class = class->element_class;
1910 if (!element_class->inited)
1911 mono_class_init (element_class);
1913 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1914 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1915 mono_class_setup_vtable (element_class);
1917 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1918 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1919 if (class->exception_type == MONO_EXCEPTION_NONE)
1920 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1921 mono_domain_unlock (domain);
1922 mono_loader_unlock ();
1924 mono_raise_exception (mono_class_get_exception_for_failure (class));
1930 * For some classes, mono_class_init () already computed class->vtable_size, and
1931 * that is all that is needed because of the vtable trampolines.
1933 if (!class->vtable_size)
1934 mono_class_setup_vtable (class);
1936 if (class->generic_class && !class->vtable)
1937 mono_class_check_vtable_constraints (class, NULL);
1939 /* Initialize klass->has_finalize */
1940 mono_class_has_finalizer (class);
1942 if (class->exception_type) {
1943 mono_domain_unlock (domain);
1944 mono_loader_unlock ();
1946 mono_raise_exception (mono_class_get_exception_for_failure (class));
1950 vtable_slots = class->vtable_size;
1951 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1952 class_size = mono_class_data_size (class);
1957 if (class->interface_offsets_count) {
1958 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1959 mono_stats.imt_number_of_tables++;
1960 mono_stats.imt_tables_size += imt_table_bytes;
1962 imt_table_bytes = 0;
1965 imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
1968 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1970 mono_stats.used_class_count++;
1971 mono_stats.class_vtable_size += vtable_size;
1973 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1974 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1975 g_assert (!((gsize)vt & 7));
1978 vt->rank = class->rank;
1979 vt->domain = domain;
1981 mono_class_compute_gc_descriptor (class);
1983 * We can't use typed allocation in the non-root domains, since the
1984 * collector needs the GC descriptor stored in the vtable even after
1985 * the mempool containing the vtable is destroyed when the domain is
1986 * unloaded. An alternative might be to allocate vtables in the GC
1987 * heap, but this does not seem to work (it leads to crashes inside
1988 * libgc). If that approach is tried, two gc descriptors need to be
1989 * allocated for each class: one for the root domain, and one for all
1990 * other domains. The second descriptor should contain a bit for the
1991 * vtable field in MonoObject, since we can no longer assume the
1992 * vtable is reachable by other roots after the appdomain is unloaded.
1994 #ifdef HAVE_BOEHM_GC
1995 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1996 vt->gc_descr = GC_NO_DESCRIPTOR;
1999 vt->gc_descr = class->gc_descr;
2001 gc_bits = mono_gc_get_vtable_bits (class);
2002 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2004 vt->gc_bits = gc_bits;
2007 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2008 if (class->has_static_refs) {
2009 gpointer statics_gc_descr;
2011 gsize default_bitmap [4] = {0};
2014 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2015 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2016 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2017 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2018 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2019 if (bitmap != default_bitmap)
2022 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2024 vt->has_static_fields = TRUE;
2025 mono_stats.class_static_data_size += class_size;
2030 while ((field = mono_class_get_fields (class, &iter))) {
2031 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2033 if (mono_field_is_deleted (field))
2035 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2036 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2037 if (special_static != SPECIAL_STATIC_NONE) {
2038 guint32 size, offset;
2040 gsize default_bitmap [4] = {0};
2045 if (mono_type_is_reference (field->type)) {
2046 default_bitmap [0] = 1;
2048 bitmap = default_bitmap;
2049 } else if (mono_type_is_struct (field->type)) {
2050 fclass = mono_class_from_mono_type (field->type);
2051 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2052 numbits = max_set + 1;
2054 default_bitmap [0] = 0;
2056 bitmap = default_bitmap;
2058 size = mono_type_size (field->type, &align);
2059 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2060 if (!domain->special_static_fields)
2061 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2062 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2063 if (bitmap != default_bitmap)
2066 * This marks the field as special static to speed up the
2067 * checks in mono_field_static_get/set_value ().
2073 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2074 MonoClass *fklass = mono_class_from_mono_type (field->type);
2075 const char *data = mono_field_get_data (field);
2077 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2078 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2079 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2082 if (fklass->valuetype) {
2083 memcpy (t, data, mono_class_value_size (fklass, NULL));
2085 /* it's a pointer type: add check */
2086 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2093 vt->max_interface_id = class->max_interface_id;
2094 vt->interface_bitmap = class->interface_bitmap;
2096 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2097 // class->name, class->interface_offsets_count);
2099 if (! ARCH_USE_IMT) {
2100 /* initialize interface offsets */
2101 for (i = 0; i < class->interface_offsets_count; ++i) {
2102 int interface_id = class->interfaces_packed [i]->interface_id;
2103 int slot = class->interface_offsets_packed [i];
2104 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2108 /* Initialize vtable */
2109 if (callbacks.get_vtable_trampoline) {
2110 // This also covers the AOT case
2111 for (i = 0; i < class->vtable_size; ++i) {
2112 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2115 mono_class_setup_vtable (class);
2117 for (i = 0; i < class->vtable_size; ++i) {
2120 if ((cm = class->vtable [i]))
2121 vt->vtable [i] = arch_create_jit_trampoline (cm);
2125 if (ARCH_USE_IMT && imt_table_bytes) {
2126 /* Now that the vtable is full, we can actually fill up the IMT */
2127 if (callbacks.get_imt_trampoline) {
2128 /* lazy construction of the IMT entries enabled */
2129 for (i = 0; i < MONO_IMT_SIZE; ++i)
2130 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2132 build_imt (class, vt, domain, interface_offsets, NULL);
2137 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2138 * re-acquire them and check if another thread has created the vtable in the meantime.
2140 /* Special case System.MonoType to avoid infinite recursion */
2141 if (class != mono_defaults.monotype_class) {
2142 /*FIXME check for OOM*/
2143 vt->type = mono_type_get_object (domain, &class->byval_arg);
2144 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2145 /* This is unregistered in
2146 unregister_vtable_reflection_type() in
2148 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2151 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2153 /* class_vtable_array keeps an array of created vtables
2155 g_ptr_array_add (domain->class_vtable_array, vt);
2156 /* class->runtime_info is protected by the loader lock, both when
2157 * it it enlarged and when it is stored info.
2161 * Store the vtable in class->runtime_info.
2162 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2164 mono_memory_barrier ();
2166 old_info = class->runtime_info;
2167 if (old_info && old_info->max_domain >= domain->domain_id) {
2168 /* someone already created a large enough runtime info */
2169 old_info->domain_vtables [domain->domain_id] = vt;
2171 int new_size = domain->domain_id;
2173 new_size = MAX (new_size, old_info->max_domain);
2175 /* make the new size a power of two */
2177 while (new_size > i)
2180 /* this is a bounded memory retention issue: may want to
2181 * handle it differently when we'll have a rcu-like system.
2183 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2184 runtime_info->max_domain = new_size - 1;
2185 /* copy the stuff from the older info */
2187 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2189 runtime_info->domain_vtables [domain->domain_id] = vt;
2191 mono_memory_barrier ();
2192 class->runtime_info = runtime_info;
2195 if (class == mono_defaults.monotype_class) {
2196 /*FIXME check for OOM*/
2197 vt->type = mono_type_get_object (domain, &class->byval_arg);
2198 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2199 /* This is unregistered in
2200 unregister_vtable_reflection_type() in
2202 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2205 mono_domain_unlock (domain);
2206 mono_loader_unlock ();
2208 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2209 if (mono_security_enabled () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2210 mono_raise_exception (mono_class_get_exception_for_failure (class));
2212 /* make sure the parent is initialized */
2213 /*FIXME shouldn't this fail the current type?*/
2215 mono_class_vtable_full (domain, class->parent, raise_on_error);
2220 #ifndef DISABLE_REMOTING
2222 * mono_class_proxy_vtable:
2223 * @domain: the application domain
2224 * @remove_class: the remote class
2226 * Creates a vtable for transparent proxies. It is basically
2227 * a copy of the real vtable of the class wrapped in @remote_class,
2228 * but all function pointers invoke the remoting functions, and
2229 * vtable->klass points to the transparent proxy class, and not to @class.
2232 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2235 MonoVTable *vt, *pvt;
2236 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2238 GSList *extra_interfaces = NULL;
2239 MonoClass *class = remote_class->proxy_class;
2240 gpointer *interface_offsets;
2243 size_t imt_table_bytes;
2245 #ifdef COMPRESSED_INTERFACE_BITMAP
2249 vt = mono_class_vtable (domain, class);
2250 g_assert (vt); /*FIXME property handle failure*/
2251 max_interface_id = vt->max_interface_id;
2253 /* Calculate vtable space for extra interfaces */
2254 for (j = 0; j < remote_class->interface_count; j++) {
2255 MonoClass* iclass = remote_class->interfaces[j];
2259 /*FIXME test for interfaces with variant generic arguments*/
2260 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2261 continue; /* interface implemented by the class */
2262 if (g_slist_find (extra_interfaces, iclass))
2265 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2267 method_count = mono_class_num_methods (iclass);
2269 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2270 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2272 for (i = 0; i < ifaces->len; ++i) {
2273 MonoClass *ic = g_ptr_array_index (ifaces, i);
2274 /*FIXME test for interfaces with variant generic arguments*/
2275 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2276 continue; /* interface implemented by the class */
2277 if (g_slist_find (extra_interfaces, ic))
2279 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2280 method_count += mono_class_num_methods (ic);
2282 g_ptr_array_free (ifaces, TRUE);
2285 extra_interface_vtsize += method_count * sizeof (gpointer);
2286 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2290 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2291 mono_stats.imt_number_of_tables++;
2292 mono_stats.imt_tables_size += imt_table_bytes;
2294 imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
2297 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2299 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2301 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2302 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2303 g_assert (!((gsize)pvt & 7));
2305 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2307 pvt->klass = mono_defaults.transparent_proxy_class;
2308 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2309 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2311 /* initialize vtable */
2312 mono_class_setup_vtable (class);
2313 for (i = 0; i < class->vtable_size; ++i) {
2316 if ((cm = class->vtable [i]))
2317 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2319 pvt->vtable [i] = NULL;
2322 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2323 /* create trampolines for abstract methods */
2324 for (k = class; k; k = k->parent) {
2326 gpointer iter = NULL;
2327 while ((m = mono_class_get_methods (k, &iter)))
2328 if (!pvt->vtable [m->slot])
2329 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2333 pvt->max_interface_id = max_interface_id;
2334 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2335 #ifdef COMPRESSED_INTERFACE_BITMAP
2336 bitmap = g_malloc0 (bsize);
2338 bitmap = mono_domain_alloc0 (domain, bsize);
2341 if (! ARCH_USE_IMT) {
2342 /* initialize interface offsets */
2343 for (i = 0; i < class->interface_offsets_count; ++i) {
2344 int interface_id = class->interfaces_packed [i]->interface_id;
2345 int slot = class->interface_offsets_packed [i];
2346 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2349 for (i = 0; i < class->interface_offsets_count; ++i) {
2350 int interface_id = class->interfaces_packed [i]->interface_id;
2351 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2354 if (extra_interfaces) {
2355 int slot = class->vtable_size;
2361 /* Create trampolines for the methods of the interfaces */
2362 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2363 interf = list_item->data;
2365 if (! ARCH_USE_IMT) {
2366 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2368 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2372 while ((cm = mono_class_get_methods (interf, &iter)))
2373 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2375 slot += mono_class_num_methods (interf);
2377 if (! ARCH_USE_IMT) {
2378 g_slist_free (extra_interfaces);
2383 /* Now that the vtable is full, we can actually fill up the IMT */
2384 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2385 if (extra_interfaces) {
2386 g_slist_free (extra_interfaces);
2390 #ifdef COMPRESSED_INTERFACE_BITMAP
2391 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2392 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2393 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2396 pvt->interface_bitmap = bitmap;
2401 #endif /* DISABLE_REMOTING */
2404 * mono_class_field_is_special_static:
2406 * Returns whether @field is a thread/context static field.
2409 mono_class_field_is_special_static (MonoClassField *field)
2411 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2413 if (mono_field_is_deleted (field))
2415 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2416 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2423 * mono_class_field_get_special_static_type:
2424 * @field: The MonoClassField describing the field.
2426 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2427 * SPECIAL_STATIC_NONE otherwise.
2430 mono_class_field_get_special_static_type (MonoClassField *field)
2432 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2433 return SPECIAL_STATIC_NONE;
2434 if (mono_field_is_deleted (field))
2435 return SPECIAL_STATIC_NONE;
2436 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2437 return field_is_special_static (field->parent, field);
2438 return SPECIAL_STATIC_NONE;
2442 * mono_class_has_special_static_fields:
2444 * Returns whenever @klass has any thread/context static fields.
2447 mono_class_has_special_static_fields (MonoClass *klass)
2449 MonoClassField *field;
2453 while ((field = mono_class_get_fields (klass, &iter))) {
2454 g_assert (field->parent == klass);
2455 if (mono_class_field_is_special_static (field))
2462 #ifndef DISABLE_REMOTING
2464 * create_remote_class_key:
2465 * Creates an array of pointers that can be used as a hash key for a remote class.
2466 * The first element of the array is the number of pointers.
2469 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2474 if (remote_class == NULL) {
2475 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2476 key = g_malloc (sizeof(gpointer) * 3);
2477 key [0] = GINT_TO_POINTER (2);
2478 key [1] = mono_defaults.marshalbyrefobject_class;
2479 key [2] = extra_class;
2481 key = g_malloc (sizeof(gpointer) * 2);
2482 key [0] = GINT_TO_POINTER (1);
2483 key [1] = extra_class;
2486 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2487 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2488 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2489 key [1] = remote_class->proxy_class;
2491 // Keep the list of interfaces sorted
2492 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2493 if (extra_class && remote_class->interfaces [i] > extra_class) {
2494 key [j++] = extra_class;
2497 key [j] = remote_class->interfaces [i];
2500 key [j] = extra_class;
2502 // Replace the old class. The interface list is the same
2503 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2504 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2505 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2506 for (i = 0; i < remote_class->interface_count; i++)
2507 key [2 + i] = remote_class->interfaces [i];
2515 * copy_remote_class_key:
2517 * Make a copy of KEY in the domain and return the copy.
2520 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2522 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2523 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2525 memcpy (mp_key, key, key_size);
2531 * mono_remote_class:
2532 * @domain: the application domain
2533 * @class_name: name of the remote class
2535 * Creates and initializes a MonoRemoteClass object for a remote type.
2537 * Can raise an exception on failure.
2540 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2543 MonoRemoteClass *rc;
2544 gpointer* key, *mp_key;
2547 key = create_remote_class_key (NULL, proxy_class);
2549 mono_domain_lock (domain);
2550 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2554 mono_domain_unlock (domain);
2558 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2559 if (!mono_error_ok (&error)) {
2561 mono_domain_unlock (domain);
2562 mono_error_raise_exception (&error);
2565 mp_key = copy_remote_class_key (domain, key);
2569 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2570 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2571 rc->interface_count = 1;
2572 rc->interfaces [0] = proxy_class;
2573 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2575 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2576 rc->interface_count = 0;
2577 rc->proxy_class = proxy_class;
2580 rc->default_vtable = NULL;
2581 rc->xdomain_vtable = NULL;
2582 rc->proxy_class_name = name;
2583 #ifndef DISABLE_PERFCOUNTERS
2584 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2587 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2589 mono_domain_unlock (domain);
2594 * clone_remote_class:
2595 * Creates a copy of the remote_class, adding the provided class or interface
2597 static MonoRemoteClass*
2598 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2600 MonoRemoteClass *rc;
2601 gpointer* key, *mp_key;
2603 key = create_remote_class_key (remote_class, extra_class);
2604 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2610 mp_key = copy_remote_class_key (domain, key);
2614 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2616 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2617 rc->proxy_class = remote_class->proxy_class;
2618 rc->interface_count = remote_class->interface_count + 1;
2620 // Keep the list of interfaces sorted, since the hash key of
2621 // the remote class depends on this
2622 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2623 if (remote_class->interfaces [i] > extra_class && i == j)
2624 rc->interfaces [j++] = extra_class;
2625 rc->interfaces [j] = remote_class->interfaces [i];
2628 rc->interfaces [j] = extra_class;
2630 // Replace the old class. The interface array is the same
2631 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2632 rc->proxy_class = extra_class;
2633 rc->interface_count = remote_class->interface_count;
2634 if (rc->interface_count > 0)
2635 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2638 rc->default_vtable = NULL;
2639 rc->xdomain_vtable = NULL;
2640 rc->proxy_class_name = remote_class->proxy_class_name;
2642 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2648 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2650 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2651 mono_domain_lock (domain);
2652 if (rp->target_domain_id != -1) {
2653 if (remote_class->xdomain_vtable == NULL)
2654 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2655 mono_domain_unlock (domain);
2656 mono_loader_unlock ();
2657 return remote_class->xdomain_vtable;
2659 if (remote_class->default_vtable == NULL) {
2662 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2663 klass = mono_class_from_mono_type (type);
2665 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)))
2666 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2669 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2672 mono_domain_unlock (domain);
2673 mono_loader_unlock ();
2674 return remote_class->default_vtable;
2678 * mono_upgrade_remote_class:
2679 * @domain: the application domain
2680 * @tproxy: the proxy whose remote class has to be upgraded.
2681 * @klass: class to which the remote class can be casted.
2683 * Updates the vtable of the remote class by adding the necessary method slots
2684 * and interface offsets so it can be safely casted to klass. klass can be a
2685 * class or an interface.
2688 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2690 MonoTransparentProxy *tproxy;
2691 MonoRemoteClass *remote_class;
2692 gboolean redo_vtable;
2694 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2695 mono_domain_lock (domain);
2697 tproxy = (MonoTransparentProxy*) proxy_object;
2698 remote_class = tproxy->remote_class;
2700 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2703 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2704 if (remote_class->interfaces [i] == klass)
2705 redo_vtable = FALSE;
2708 redo_vtable = (remote_class->proxy_class != klass);
2712 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2713 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2716 mono_domain_unlock (domain);
2717 mono_loader_unlock ();
2719 #endif /* DISABLE_REMOTING */
2723 * mono_object_get_virtual_method:
2724 * @obj: object to operate on.
2727 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2728 * the instance of a callvirt of method.
2731 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2734 MonoMethod **vtable;
2735 gboolean is_proxy = FALSE;
2736 MonoMethod *res = NULL;
2738 klass = mono_object_class (obj);
2739 #ifndef DISABLE_REMOTING
2740 if (klass == mono_defaults.transparent_proxy_class) {
2741 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2746 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2749 mono_class_setup_vtable (klass);
2750 vtable = klass->vtable;
2752 if (method->slot == -1) {
2753 /* method->slot might not be set for instances of generic methods */
2754 if (method->is_inflated) {
2755 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2756 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2759 g_assert_not_reached ();
2763 /* check method->slot is a valid index: perform isinstance? */
2764 if (method->slot != -1) {
2765 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2767 gboolean variance_used = FALSE;
2768 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2769 g_assert (iface_offset > 0);
2770 res = vtable [iface_offset + method->slot];
2773 res = vtable [method->slot];
2777 #ifndef DISABLE_REMOTING
2779 /* It may be an interface, abstract class method or generic method */
2780 if (!res || mono_method_signature (res)->generic_param_count)
2783 /* generic methods demand invoke_with_check */
2784 if (mono_method_signature (res)->generic_param_count)
2785 res = mono_marshal_get_remoting_invoke_with_check (res);
2788 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2789 res = mono_cominterop_get_invoke (res);
2792 res = mono_marshal_get_remoting_invoke (res);
2797 if (method->is_inflated) {
2799 /* Have to inflate the result */
2800 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2801 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2811 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2813 g_error ("runtime invoke called on uninitialized runtime");
2817 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2820 * mono_runtime_invoke:
2821 * @method: method to invoke
2822 * @obJ: object instance
2823 * @params: arguments to the method
2824 * @exc: exception information.
2826 * Invokes the method represented by @method on the object @obj.
2828 * obj is the 'this' pointer, it should be NULL for static
2829 * methods, a MonoObject* for object instances and a pointer to
2830 * the value type for value types.
2832 * The params array contains the arguments to the method with the
2833 * same convention: MonoObject* pointers for object instances and
2834 * pointers to the value type otherwise.
2836 * From unmanaged code you'll usually use the
2837 * mono_runtime_invoke() variant.
2839 * Note that this function doesn't handle virtual methods for
2840 * you, it will exec the exact method you pass: we still need to
2841 * expose a function to lookup the derived class implementation
2842 * of a virtual method (there are examples of this in the code,
2845 * You can pass NULL as the exc argument if you don't want to
2846 * catch exceptions, otherwise, *exc will be set to the exception
2847 * thrown, if any. if an exception is thrown, you can't use the
2848 * MonoObject* result from the function.
2850 * If the method returns a value type, it is boxed in an object
2854 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2858 if (mono_runtime_get_no_exec ())
2859 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2861 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2862 mono_profiler_method_start_invoke (method);
2864 result = default_mono_runtime_invoke (method, obj, params, exc);
2866 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2867 mono_profiler_method_end_invoke (method);
2873 * mono_method_get_unmanaged_thunk:
2874 * @method: method to generate a thunk for.
2876 * Returns an unmanaged->managed thunk that can be used to call
2877 * a managed method directly from C.
2879 * The thunk's C signature closely matches the managed signature:
2881 * C#: public bool Equals (object obj);
2882 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2883 * MonoObject*, MonoException**);
2885 * The 1st ("this") parameter must not be used with static methods:
2887 * C#: public static bool ReferenceEquals (object a, object b);
2888 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2891 * The last argument must be a non-null pointer of a MonoException* pointer.
2892 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2893 * exception has been thrown in managed code. Otherwise it will point
2894 * to the MonoException* caught by the thunk. In this case, the result of
2895 * the thunk is undefined:
2897 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2898 * MonoException *ex = NULL;
2899 * Equals func = mono_method_get_unmanaged_thunk (method);
2900 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2902 * // handle exception
2905 * The calling convention of the thunk matches the platform's default
2906 * convention. This means that under Windows, C declarations must
2907 * contain the __stdcall attribute:
2909 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2910 * MonoObject*, MonoException**);
2914 * Value type arguments and return values are treated as they were objects:
2916 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2917 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2919 * Arguments must be properly boxed upon trunk's invocation, while return
2920 * values must be unboxed.
2923 mono_method_get_unmanaged_thunk (MonoMethod *method)
2925 method = mono_marshal_get_thunk_invoke_wrapper (method);
2926 return mono_compile_method (method);
2930 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2934 /* object fields cannot be byref, so we don't need a
2936 gpointer *p = (gpointer*)dest;
2943 case MONO_TYPE_BOOLEAN:
2945 case MONO_TYPE_U1: {
2946 guint8 *p = (guint8*)dest;
2947 *p = value ? *(guint8*)value : 0;
2952 case MONO_TYPE_CHAR: {
2953 guint16 *p = (guint16*)dest;
2954 *p = value ? *(guint16*)value : 0;
2957 #if SIZEOF_VOID_P == 4
2962 case MONO_TYPE_U4: {
2963 gint32 *p = (gint32*)dest;
2964 *p = value ? *(gint32*)value : 0;
2967 #if SIZEOF_VOID_P == 8
2972 case MONO_TYPE_U8: {
2973 gint64 *p = (gint64*)dest;
2974 *p = value ? *(gint64*)value : 0;
2977 case MONO_TYPE_R4: {
2978 float *p = (float*)dest;
2979 *p = value ? *(float*)value : 0;
2982 case MONO_TYPE_R8: {
2983 double *p = (double*)dest;
2984 *p = value ? *(double*)value : 0;
2987 case MONO_TYPE_STRING:
2988 case MONO_TYPE_SZARRAY:
2989 case MONO_TYPE_CLASS:
2990 case MONO_TYPE_OBJECT:
2991 case MONO_TYPE_ARRAY:
2992 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2994 case MONO_TYPE_FNPTR:
2995 case MONO_TYPE_PTR: {
2996 gpointer *p = (gpointer*)dest;
2997 *p = deref_pointer? *(gpointer*)value: value;
3000 case MONO_TYPE_VALUETYPE:
3001 /* note that 't' and 'type->type' can be different */
3002 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3003 t = mono_class_enum_basetype (type->data.klass)->type;
3006 MonoClass *class = mono_class_from_mono_type (type);
3007 int size = mono_class_value_size (class, NULL);
3009 mono_gc_bzero_atomic (dest, size);
3011 mono_gc_wbarrier_value_copy (dest, value, 1, class);
3014 case MONO_TYPE_GENERICINST:
3015 t = type->data.generic_class->container_class->byval_arg.type;
3018 g_error ("got type %x", type->type);
3023 * mono_field_set_value:
3024 * @obj: Instance object
3025 * @field: MonoClassField describing the field to set
3026 * @value: The value to be set
3028 * Sets the value of the field described by @field in the object instance @obj
3029 * to the value passed in @value. This method should only be used for instance
3030 * fields. For static fields, use mono_field_static_set_value.
3032 * The value must be on the native format of the field type.
3035 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3039 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3041 dest = (char*)obj + field->offset;
3042 set_value (field->type, dest, value, FALSE);
3046 * mono_field_static_set_value:
3047 * @field: MonoClassField describing the field to set
3048 * @value: The value to be set
3050 * Sets the value of the static field described by @field
3051 * to the value passed in @value.
3053 * The value must be on the native format of the field type.
3056 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3060 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3061 /* you cant set a constant! */
3062 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3064 if (field->offset == -1) {
3065 /* Special static */
3068 mono_domain_lock (vt->domain);
3069 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3070 mono_domain_unlock (vt->domain);
3071 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3073 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3075 set_value (field->type, dest, value, FALSE);
3079 * mono_vtable_get_static_field_data:
3081 * Internal use function: return a pointer to the memory holding the static fields
3082 * for a class or NULL if there are no static fields.
3083 * This is exported only for use by the debugger.
3086 mono_vtable_get_static_field_data (MonoVTable *vt)
3088 if (!vt->has_static_fields)
3090 return vt->vtable [vt->klass->vtable_size];
3094 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3098 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3099 if (field->offset == -1) {
3100 /* Special static */
3103 mono_domain_lock (vt->domain);
3104 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3105 mono_domain_unlock (vt->domain);
3106 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3108 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3111 src = (guint8*)obj + field->offset;
3118 * mono_field_get_value:
3119 * @obj: Object instance
3120 * @field: MonoClassField describing the field to fetch information from
3121 * @value: pointer to the location where the value will be stored
3123 * Use this routine to get the value of the field @field in the object
3126 * The pointer provided by value must be of the field type, for reference
3127 * types this is a MonoObject*, for value types its the actual pointer to
3132 * mono_field_get_value (obj, int_field, &i);
3135 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3141 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3143 src = (char*)obj + field->offset;
3144 set_value (field->type, value, src, TRUE);
3148 * mono_field_get_value_object:
3149 * @domain: domain where the object will be created (if boxing)
3150 * @field: MonoClassField describing the field to fetch information from
3151 * @obj: The object instance for the field.
3153 * Returns: a new MonoObject with the value from the given field. If the
3154 * field represents a value type, the value is boxed.
3158 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3162 MonoVTable *vtable = NULL;
3164 gboolean is_static = FALSE;
3165 gboolean is_ref = FALSE;
3166 gboolean is_literal = FALSE;
3167 gboolean is_ptr = FALSE;
3169 MonoType *type = mono_field_get_type_checked (field, &error);
3171 if (!mono_error_ok (&error))
3172 mono_error_raise_exception (&error);
3174 switch (type->type) {
3175 case MONO_TYPE_STRING:
3176 case MONO_TYPE_OBJECT:
3177 case MONO_TYPE_CLASS:
3178 case MONO_TYPE_ARRAY:
3179 case MONO_TYPE_SZARRAY:
3184 case MONO_TYPE_BOOLEAN:
3187 case MONO_TYPE_CHAR:
3196 case MONO_TYPE_VALUETYPE:
3197 is_ref = type->byref;
3199 case MONO_TYPE_GENERICINST:
3200 is_ref = !mono_type_generic_inst_is_valuetype (type);
3206 g_error ("type 0x%x not handled in "
3207 "mono_field_get_value_object", type->type);
3211 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3214 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3218 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3219 if (!vtable->initialized)
3220 mono_runtime_class_init (vtable);
3228 get_default_field_value (domain, field, &o);
3229 } else if (is_static) {
3230 mono_field_static_get_value (vtable, field, &o);
3232 mono_field_get_value (obj, field, &o);
3238 static MonoMethod *m;
3244 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3245 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3251 get_default_field_value (domain, field, v);
3252 } else if (is_static) {
3253 mono_field_static_get_value (vtable, field, v);
3255 mono_field_get_value (obj, field, v);
3258 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3259 args [0] = ptr ? *ptr : NULL;
3260 args [1] = mono_type_get_object (mono_domain_get (), type);
3262 return mono_runtime_invoke (m, NULL, args, NULL);
3265 /* boxed value type */
3266 klass = mono_class_from_mono_type (type);
3268 if (mono_class_is_nullable (klass))
3269 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3271 o = mono_object_new (domain, klass);
3272 v = ((gchar *) o) + sizeof (MonoObject);
3275 get_default_field_value (domain, field, v);
3276 } else if (is_static) {
3277 mono_field_static_get_value (vtable, field, v);
3279 mono_field_get_value (obj, field, v);
3286 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3289 const char *p = blob;
3290 mono_metadata_decode_blob_size (p, &p);
3293 case MONO_TYPE_BOOLEAN:
3296 *(guint8 *) value = *p;
3298 case MONO_TYPE_CHAR:
3301 *(guint16*) value = read16 (p);
3305 *(guint32*) value = read32 (p);
3309 *(guint64*) value = read64 (p);
3312 readr4 (p, (float*) value);
3315 readr8 (p, (double*) value);
3317 case MONO_TYPE_STRING:
3318 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3320 case MONO_TYPE_CLASS:
3321 *(gpointer*) value = NULL;
3325 g_warning ("type 0x%02x should not be in constant table", type);
3331 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3333 MonoTypeEnum def_type;
3336 data = mono_class_get_field_default_value (field, &def_type);
3337 mono_get_constant_value_from_blob (domain, def_type, data, value);
3341 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3345 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3347 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3348 get_default_field_value (vt->domain, field, value);
3352 if (field->offset == -1) {
3353 /* Special static */
3354 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3355 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3357 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3359 set_value (field->type, value, src, TRUE);
3363 * mono_field_static_get_value:
3364 * @vt: vtable to the object
3365 * @field: MonoClassField describing the field to fetch information from
3366 * @value: where the value is returned
3368 * Use this routine to get the value of the static field @field value.
3370 * The pointer provided by value must be of the field type, for reference
3371 * types this is a MonoObject*, for value types its the actual pointer to
3376 * mono_field_static_get_value (vt, int_field, &i);
3379 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3381 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3385 * mono_property_set_value:
3386 * @prop: MonoProperty to set
3387 * @obj: instance object on which to act
3388 * @params: parameters to pass to the propery
3389 * @exc: optional exception
3391 * Invokes the property's set method with the given arguments on the
3392 * object instance obj (or NULL for static properties).
3394 * You can pass NULL as the exc argument if you don't want to
3395 * catch exceptions, otherwise, *exc will be set to the exception
3396 * thrown, if any. if an exception is thrown, you can't use the
3397 * MonoObject* result from the function.
3400 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3402 default_mono_runtime_invoke (prop->set, obj, params, exc);
3406 * mono_property_get_value:
3407 * @prop: MonoProperty to fetch
3408 * @obj: instance object on which to act
3409 * @params: parameters to pass to the propery
3410 * @exc: optional exception
3412 * Invokes the property's get method with the given arguments on the
3413 * object instance obj (or NULL for static properties).
3415 * You can pass NULL as the exc argument if you don't want to
3416 * catch exceptions, otherwise, *exc will be set to the exception
3417 * thrown, if any. if an exception is thrown, you can't use the
3418 * MonoObject* result from the function.
3420 * Returns: the value from invoking the get method on the property.
3423 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3425 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3429 * mono_nullable_init:
3430 * @buf: The nullable structure to initialize.
3431 * @value: the value to initialize from
3432 * @klass: the type for the object
3434 * Initialize the nullable structure pointed to by @buf from @value which
3435 * should be a boxed value type. The size of @buf should be able to hold
3436 * as much data as the @klass->instance_size (which is the number of bytes
3437 * that will be copies).
3439 * Since Nullables have variable structure, we can not define a C
3440 * structure for them.
3443 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3445 MonoClass *param_class = klass->cast_class;
3447 mono_class_setup_fields_locking (klass);
3448 g_assert (klass->fields_inited);
3450 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3451 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3453 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3455 if (param_class->has_references)
3456 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3458 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3460 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3465 * mono_nullable_box:
3466 * @buf: The buffer representing the data to be boxed
3467 * @klass: the type to box it as.
3469 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3473 mono_nullable_box (guint8 *buf, MonoClass *klass)
3475 MonoClass *param_class = klass->cast_class;
3477 mono_class_setup_fields_locking (klass);
3478 g_assert (klass->fields_inited);
3480 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3481 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3483 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3484 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3485 if (param_class->has_references)
3486 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3488 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3496 * mono_get_delegate_invoke:
3497 * @klass: The delegate class
3499 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3502 mono_get_delegate_invoke (MonoClass *klass)
3506 /* This is called at runtime, so avoid the slower search in metadata */
3507 mono_class_setup_methods (klass);
3508 if (klass->exception_type)
3510 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3515 * mono_get_delegate_begin_invoke:
3516 * @klass: The delegate class
3518 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3521 mono_get_delegate_begin_invoke (MonoClass *klass)
3525 /* This is called at runtime, so avoid the slower search in metadata */
3526 mono_class_setup_methods (klass);
3527 if (klass->exception_type)
3529 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3534 * mono_get_delegate_end_invoke:
3535 * @klass: The delegate class
3537 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3540 mono_get_delegate_end_invoke (MonoClass *klass)
3544 /* This is called at runtime, so avoid the slower search in metadata */
3545 mono_class_setup_methods (klass);
3546 if (klass->exception_type)
3548 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3553 * mono_runtime_delegate_invoke:
3554 * @delegate: pointer to a delegate object.
3555 * @params: parameters for the delegate.
3556 * @exc: Pointer to the exception result.
3558 * Invokes the delegate method @delegate with the parameters provided.
3560 * You can pass NULL as the exc argument if you don't want to
3561 * catch exceptions, otherwise, *exc will be set to the exception
3562 * thrown, if any. if an exception is thrown, you can't use the
3563 * MonoObject* result from the function.
3566 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3569 MonoClass *klass = delegate->vtable->klass;
3571 im = mono_get_delegate_invoke (klass);
3573 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3575 return mono_runtime_invoke (im, delegate, params, exc);
3578 static char **main_args = NULL;
3579 static int num_main_args = 0;
3582 * mono_runtime_get_main_args:
3584 * Returns: a MonoArray with the arguments passed to the main program
3587 mono_runtime_get_main_args (void)
3591 MonoDomain *domain = mono_domain_get ();
3593 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3595 for (i = 0; i < num_main_args; ++i)
3596 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3602 free_main_args (void)
3606 for (i = 0; i < num_main_args; ++i)
3607 g_free (main_args [i]);
3614 * mono_runtime_set_main_args:
3615 * @argc: number of arguments from the command line
3616 * @argv: array of strings from the command line
3618 * Set the command line arguments from an embedding application that doesn't otherwise call
3619 * mono_runtime_run_main ().
3622 mono_runtime_set_main_args (int argc, char* argv[])
3627 main_args = g_new0 (char*, argc);
3628 num_main_args = argc;
3630 for (i = 0; i < argc; ++i) {
3633 utf8_arg = mono_utf8_from_external (argv[i]);
3634 if (utf8_arg == NULL) {
3635 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3636 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3640 main_args [i] = utf8_arg;
3647 * mono_runtime_run_main:
3648 * @method: the method to start the application with (usually Main)
3649 * @argc: number of arguments from the command line
3650 * @argv: array of strings from the command line
3651 * @exc: excetption results
3653 * Execute a standard Main() method (argc/argv contains the
3654 * executable name). This method also sets the command line argument value
3655 * needed by System.Environment.
3660 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3664 MonoArray *args = NULL;
3665 MonoDomain *domain = mono_domain_get ();
3666 gchar *utf8_fullpath;
3667 MonoMethodSignature *sig;
3669 g_assert (method != NULL);
3671 mono_thread_set_main (mono_thread_current ());
3673 main_args = g_new0 (char*, argc);
3674 num_main_args = argc;
3676 if (!g_path_is_absolute (argv [0])) {
3677 gchar *basename = g_path_get_basename (argv [0]);
3678 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3682 utf8_fullpath = mono_utf8_from_external (fullpath);
3683 if(utf8_fullpath == NULL) {
3684 /* Printing the arg text will cause glib to
3685 * whinge about "Invalid UTF-8", but at least
3686 * its relevant, and shows the problem text
3689 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3690 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3697 utf8_fullpath = mono_utf8_from_external (argv[0]);
3698 if(utf8_fullpath == NULL) {
3699 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3700 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3705 main_args [0] = utf8_fullpath;
3707 for (i = 1; i < argc; ++i) {
3710 utf8_arg=mono_utf8_from_external (argv[i]);
3711 if(utf8_arg==NULL) {
3712 /* Ditto the comment about Invalid UTF-8 here */
3713 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3714 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3718 main_args [i] = utf8_arg;
3723 sig = mono_method_signature (method);
3725 g_print ("Unable to load Main method.\n");
3729 if (sig->param_count) {
3730 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3731 for (i = 0; i < argc; ++i) {
3732 /* The encodings should all work, given that
3733 * we've checked all these args for the
3736 gchar *str = mono_utf8_from_external (argv [i]);
3737 MonoString *arg = mono_string_new (domain, str);
3738 mono_array_setref (args, i, arg);
3742 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3745 mono_assembly_set_main (method->klass->image->assembly);
3747 return mono_runtime_exec_main (method, args, exc);
3751 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3753 static MonoMethod *serialize_method;
3758 if (!serialize_method) {
3759 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3760 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3763 if (!serialize_method) {
3768 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3772 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3780 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3782 static MonoMethod *deserialize_method;
3787 if (!deserialize_method) {
3788 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3789 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3791 if (!deserialize_method) {
3798 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3805 #ifndef DISABLE_REMOTING
3807 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3809 static MonoMethod *get_proxy_method;
3811 MonoDomain *domain = mono_domain_get ();
3812 MonoRealProxy *real_proxy;
3813 MonoReflectionType *reflection_type;
3814 MonoTransparentProxy *transparent_proxy;
3816 if (!get_proxy_method)
3817 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3819 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3821 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3822 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3824 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3825 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3828 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3832 return (MonoObject*) transparent_proxy;
3834 #endif /* DISABLE_REMOTING */
3837 * mono_object_xdomain_representation
3839 * @target_domain: a domain
3840 * @exc: pointer to a MonoObject*
3842 * Creates a representation of obj in the domain target_domain. This
3843 * is either a copy of obj arrived through via serialization and
3844 * deserialization or a proxy, depending on whether the object is
3845 * serializable or marshal by ref. obj must not be in target_domain.
3847 * If the object cannot be represented in target_domain, NULL is
3848 * returned and *exc is set to an appropriate exception.
3851 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3853 MonoObject *deserialized = NULL;
3854 gboolean failure = FALSE;
3858 #ifndef DISABLE_REMOTING
3859 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3860 deserialized = make_transparent_proxy (obj, &failure, exc);
3865 MonoDomain *domain = mono_domain_get ();
3866 MonoObject *serialized;
3868 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3869 serialized = serialize_object (obj, &failure, exc);
3870 mono_domain_set_internal_with_options (target_domain, FALSE);
3872 deserialized = deserialize_object (serialized, &failure, exc);
3873 if (domain != target_domain)
3874 mono_domain_set_internal_with_options (domain, FALSE);
3877 return deserialized;
3880 /* Used in call_unhandled_exception_delegate */
3882 create_unhandled_exception_eventargs (MonoObject *exc)
3886 MonoMethod *method = NULL;
3887 MonoBoolean is_terminating = TRUE;
3890 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3893 mono_class_init (klass);
3895 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3896 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3900 args [1] = &is_terminating;
3902 obj = mono_object_new (mono_domain_get (), klass);
3903 mono_runtime_invoke (method, obj, args, NULL);
3908 /* Used in mono_unhandled_exception */
3910 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3911 MonoObject *e = NULL;
3913 MonoDomain *current_domain = mono_domain_get ();
3915 if (domain != current_domain)
3916 mono_domain_set_internal_with_options (domain, FALSE);
3918 g_assert (domain == mono_object_domain (domain->domain));
3920 if (mono_object_domain (exc) != domain) {
3921 MonoObject *serialization_exc;
3923 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3925 if (serialization_exc) {
3927 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3930 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3931 "System.Runtime.Serialization", "SerializationException",
3932 "Could not serialize unhandled exception.");
3936 g_assert (mono_object_domain (exc) == domain);
3938 pa [0] = domain->domain;
3939 pa [1] = create_unhandled_exception_eventargs (exc);
3940 mono_runtime_delegate_invoke (delegate, pa, &e);
3942 if (domain != current_domain)
3943 mono_domain_set_internal_with_options (current_domain, FALSE);
3947 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3948 if (!mono_error_ok (&error)) {
3949 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3950 mono_error_cleanup (&error);
3952 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3958 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3961 * mono_runtime_unhandled_exception_policy_set:
3962 * @policy: the new policy
3964 * This is a VM internal routine.
3966 * Sets the runtime policy for handling unhandled exceptions.
3969 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3970 runtime_unhandled_exception_policy = policy;
3974 * mono_runtime_unhandled_exception_policy_get:
3976 * This is a VM internal routine.
3978 * Gets the runtime policy for handling unhandled exceptions.
3980 MonoRuntimeUnhandledExceptionPolicy
3981 mono_runtime_unhandled_exception_policy_get (void) {
3982 return runtime_unhandled_exception_policy;
3986 * mono_unhandled_exception:
3987 * @exc: exception thrown
3989 * This is a VM internal routine.
3991 * We call this function when we detect an unhandled exception
3992 * in the default domain.
3994 * It invokes the * UnhandledException event in AppDomain or prints
3995 * a warning to the console
3998 mono_unhandled_exception (MonoObject *exc)
4000 MonoDomain *current_domain = mono_domain_get ();
4001 MonoDomain *root_domain = mono_get_root_domain ();
4002 MonoClassField *field;
4003 MonoObject *current_appdomain_delegate;
4004 MonoObject *root_appdomain_delegate;
4006 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
4007 "UnhandledException");
4010 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
4011 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
4012 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
4013 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
4014 if (current_domain != root_domain) {
4015 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
4017 current_appdomain_delegate = NULL;
4020 /* set exitcode only if we will abort the process */
4021 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
4023 mono_environment_exitcode_set (1);
4024 mono_print_unhandled_exception (exc);
4026 if (root_appdomain_delegate) {
4027 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4029 if (current_appdomain_delegate) {
4030 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4037 * mono_runtime_exec_managed_code:
4038 * @domain: Application domain
4039 * @main_func: function to invoke from the execution thread
4040 * @main_args: parameter to the main_func
4042 * Launch a new thread to execute a function
4044 * main_func is called back from the thread with main_args as the
4045 * parameter. The callback function is expected to start Main()
4046 * eventually. This function then waits for all managed threads to
4048 * It is not necesseray anymore to execute managed code in a subthread,
4049 * so this function should not be used anymore by default: just
4050 * execute the code and then call mono_thread_manage ().
4053 mono_runtime_exec_managed_code (MonoDomain *domain,
4054 MonoMainThreadFunc main_func,
4057 mono_thread_create (domain, main_func, main_args);
4059 mono_thread_manage ();
4063 * Execute a standard Main() method (args doesn't contain the
4067 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4072 MonoCustomAttrInfo* cinfo;
4073 gboolean has_stathread_attribute;
4074 MonoInternalThread* thread = mono_thread_internal_current ();
4080 domain = mono_object_domain (args);
4081 if (!domain->entry_assembly) {
4083 MonoAssembly *assembly;
4085 assembly = method->klass->image->assembly;
4086 domain->entry_assembly = assembly;
4087 /* Domains created from another domain already have application_base and configuration_file set */
4088 if (domain->setup->application_base == NULL) {
4089 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4092 if (domain->setup->configuration_file == NULL) {
4093 str = g_strconcat (assembly->image->name, ".config", NULL);
4094 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4096 mono_set_private_bin_path_from_config (domain);
4100 cinfo = mono_custom_attrs_from_method (method);
4102 static MonoClass *stathread_attribute = NULL;
4103 if (!stathread_attribute)
4104 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4105 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4107 mono_custom_attrs_free (cinfo);
4109 has_stathread_attribute = FALSE;
4111 if (has_stathread_attribute) {
4112 thread->apartment_state = ThreadApartmentState_STA;
4114 thread->apartment_state = ThreadApartmentState_MTA;
4116 mono_thread_init_apartment_state ();
4118 /* FIXME: check signature of method */
4119 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4121 res = mono_runtime_invoke (method, NULL, pa, exc);
4123 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4127 mono_environment_exitcode_set (rval);
4129 mono_runtime_invoke (method, NULL, pa, exc);
4133 /* If the return type of Main is void, only
4134 * set the exitcode if an exception was thrown
4135 * (we don't want to blow away an
4136 * explicitly-set exit code)
4139 mono_environment_exitcode_set (rval);
4147 * mono_install_runtime_invoke:
4148 * @func: Function to install
4150 * This is a VM internal routine
4153 mono_install_runtime_invoke (MonoInvokeFunc func)
4155 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4160 * mono_runtime_invoke_array:
4161 * @method: method to invoke
4162 * @obJ: object instance
4163 * @params: arguments to the method
4164 * @exc: exception information.
4166 * Invokes the method represented by @method on the object @obj.
4168 * obj is the 'this' pointer, it should be NULL for static
4169 * methods, a MonoObject* for object instances and a pointer to
4170 * the value type for value types.
4172 * The params array contains the arguments to the method with the
4173 * same convention: MonoObject* pointers for object instances and
4174 * pointers to the value type otherwise. The _invoke_array
4175 * variant takes a C# object[] as the params argument (MonoArray
4176 * *params): in this case the value types are boxed inside the
4177 * respective reference representation.
4179 * From unmanaged code you'll usually use the
4180 * mono_runtime_invoke() variant.
4182 * Note that this function doesn't handle virtual methods for
4183 * you, it will exec the exact method you pass: we still need to
4184 * expose a function to lookup the derived class implementation
4185 * of a virtual method (there are examples of this in the code,
4188 * You can pass NULL as the exc argument if you don't want to
4189 * catch exceptions, otherwise, *exc will be set to the exception
4190 * thrown, if any. if an exception is thrown, you can't use the
4191 * MonoObject* result from the function.
4193 * If the method returns a value type, it is boxed in an object
4197 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4200 MonoMethodSignature *sig = mono_method_signature (method);
4201 gpointer *pa = NULL;
4204 gboolean has_byref_nullables = FALSE;
4206 if (NULL != params) {
4207 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4208 for (i = 0; i < mono_array_length (params); i++) {
4209 MonoType *t = sig->params [i];
4215 case MONO_TYPE_BOOLEAN:
4218 case MONO_TYPE_CHAR:
4227 case MONO_TYPE_VALUETYPE:
4228 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4229 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4230 pa [i] = mono_array_get (params, MonoObject*, i);
4232 has_byref_nullables = TRUE;
4234 /* MS seems to create the objects if a null is passed in */
4235 if (!mono_array_get (params, MonoObject*, i))
4236 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4240 * We can't pass the unboxed vtype byref to the callee, since
4241 * that would mean the callee would be able to modify boxed
4242 * primitive types. So we (and MS) make a copy of the boxed
4243 * object, pass that to the callee, and replace the original
4244 * boxed object in the arg array with the copy.
4246 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4247 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4248 mono_array_setref (params, i, copy);
4251 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4254 case MONO_TYPE_STRING:
4255 case MONO_TYPE_OBJECT:
4256 case MONO_TYPE_CLASS:
4257 case MONO_TYPE_ARRAY:
4258 case MONO_TYPE_SZARRAY:
4260 pa [i] = mono_array_addr (params, MonoObject*, i);
4261 // FIXME: I need to check this code path
4263 pa [i] = mono_array_get (params, MonoObject*, i);
4265 case MONO_TYPE_GENERICINST:
4267 t = &t->data.generic_class->container_class->this_arg;
4269 t = &t->data.generic_class->container_class->byval_arg;
4271 case MONO_TYPE_PTR: {
4274 /* The argument should be an IntPtr */
4275 arg = mono_array_get (params, MonoObject*, i);
4279 g_assert (arg->vtable->klass == mono_defaults.int_class);
4280 pa [i] = ((MonoIntPtr*)arg)->m_value;
4285 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4290 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4293 if (mono_class_is_nullable (method->klass)) {
4294 /* Need to create a boxed vtype instead */
4300 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4304 obj = mono_object_new (mono_domain_get (), method->klass);
4305 g_assert (obj); /*maybe we should raise a TLE instead?*/
4306 #ifndef DISABLE_REMOTING
4307 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4308 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4311 if (method->klass->valuetype)
4312 o = mono_object_unbox (obj);
4315 } else if (method->klass->valuetype) {
4316 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4319 mono_runtime_invoke (method, o, pa, exc);
4322 if (mono_class_is_nullable (method->klass)) {
4323 MonoObject *nullable;
4325 /* Convert the unboxed vtype into a Nullable structure */
4326 nullable = mono_object_new (mono_domain_get (), method->klass);
4328 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4329 obj = mono_object_unbox (nullable);
4332 /* obj must be already unboxed if needed */
4333 res = mono_runtime_invoke (method, obj, pa, exc);
4335 if (sig->ret->type == MONO_TYPE_PTR) {
4336 MonoClass *pointer_class;
4337 static MonoMethod *box_method;
4339 MonoObject *box_exc;
4342 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4343 * convert it to a Pointer object.
4345 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4347 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4349 g_assert (res->vtable->klass == mono_defaults.int_class);
4350 box_args [0] = ((MonoIntPtr*)res)->m_value;
4351 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4352 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4353 g_assert (!box_exc);
4356 if (has_byref_nullables) {
4358 * The runtime invoke wrapper already converted byref nullables back,
4359 * and stored them in pa, we just need to copy them back to the
4362 for (i = 0; i < mono_array_length (params); i++) {
4363 MonoType *t = sig->params [i];
4365 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4366 mono_array_setref (params, i, pa [i]);
4375 arith_overflow (void)
4377 mono_raise_exception (mono_get_exception_overflow ());
4381 * mono_object_allocate:
4382 * @size: number of bytes to allocate
4384 * This is a very simplistic routine until we have our GC-aware
4387 * Returns: an allocated object of size @size, or NULL on failure.
4389 static inline void *
4390 mono_object_allocate (size_t size, MonoVTable *vtable)
4393 ALLOC_OBJECT (o, vtable, size);
4399 * mono_object_allocate_ptrfree:
4400 * @size: number of bytes to allocate
4402 * Note that the memory allocated is not zeroed.
4403 * Returns: an allocated object of size @size, or NULL on failure.
4405 static inline void *
4406 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4409 ALLOC_PTRFREE (o, vtable, size);
4413 static inline void *
4414 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4417 ALLOC_TYPED (o, size, vtable);
4424 * @klass: the class of the object that we want to create
4426 * Returns: a newly created object whose definition is
4427 * looked up using @klass. This will not invoke any constructors,
4428 * so the consumer of this routine has to invoke any constructors on
4429 * its own to initialize the object.
4431 * It returns NULL on failure.
4434 mono_object_new (MonoDomain *domain, MonoClass *klass)
4438 MONO_ARCH_SAVE_REGS;
4439 vtable = mono_class_vtable (domain, klass);
4442 return mono_object_new_specific (vtable);
4446 * mono_object_new_pinned:
4448 * Same as mono_object_new, but the returned object will be pinned.
4449 * For SGEN, these objects will only be freed at appdomain unload.
4452 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4456 MONO_ARCH_SAVE_REGS;
4457 vtable = mono_class_vtable (domain, klass);
4462 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4464 return mono_object_new_specific (vtable);
4469 * mono_object_new_specific:
4470 * @vtable: the vtable of the object that we want to create
4472 * Returns: A newly created object with class and domain specified
4476 mono_object_new_specific (MonoVTable *vtable)
4480 MONO_ARCH_SAVE_REGS;
4482 /* check for is_com_object for COM Interop */
4483 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4486 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4489 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4492 mono_class_init (klass);
4494 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4496 vtable->domain->create_proxy_for_type_method = im;
4499 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4501 o = mono_runtime_invoke (im, NULL, pa, NULL);
4502 if (o != NULL) return o;
4505 return mono_object_new_alloc_specific (vtable);
4509 mono_object_new_alloc_specific (MonoVTable *vtable)
4513 if (!vtable->klass->has_references) {
4514 o = mono_object_new_ptrfree (vtable);
4515 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4516 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4518 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4519 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4521 if (G_UNLIKELY (vtable->klass->has_finalize))
4522 mono_object_register_finalizer (o);
4524 if (G_UNLIKELY (profile_allocs))
4525 mono_profiler_allocation (o, vtable->klass);
4530 mono_object_new_fast (MonoVTable *vtable)
4533 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4538 mono_object_new_ptrfree (MonoVTable *vtable)
4541 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4542 #if NEED_TO_ZERO_PTRFREE
4543 /* an inline memset is much faster for the common vcase of small objects
4544 * note we assume the allocated size is a multiple of sizeof (void*).
4546 if (vtable->klass->instance_size < 128) {
4548 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4549 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4555 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4562 mono_object_new_ptrfree_box (MonoVTable *vtable)
4565 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4566 /* the object will be boxed right away, no need to memzero it */
4571 * mono_class_get_allocation_ftn:
4573 * @for_box: the object will be used for boxing
4574 * @pass_size_in_words:
4576 * Return the allocation function appropriate for the given class.
4580 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4582 *pass_size_in_words = FALSE;
4584 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4585 profile_allocs = FALSE;
4587 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4588 return mono_object_new_specific;
4590 if (!vtable->klass->has_references) {
4591 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4593 return mono_object_new_ptrfree_box;
4594 return mono_object_new_ptrfree;
4597 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4599 return mono_object_new_fast;
4602 * FIXME: This is actually slower than mono_object_new_fast, because
4603 * of the overhead of parameter passing.
4606 *pass_size_in_words = TRUE;
4607 #ifdef GC_REDIRECT_TO_LOCAL
4608 return GC_local_gcj_fast_malloc;
4610 return GC_gcj_fast_malloc;
4615 return mono_object_new_specific;
4619 * mono_object_new_from_token:
4620 * @image: Context where the type_token is hosted
4621 * @token: a token of the type that we want to create
4623 * Returns: A newly created object whose definition is
4624 * looked up using @token in the @image image
4627 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4632 class = mono_class_get_checked (image, token, &error);
4633 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4635 return mono_object_new (domain, class);
4640 * mono_object_clone:
4641 * @obj: the object to clone
4643 * Returns: A newly created object who is a shallow copy of @obj
4646 mono_object_clone (MonoObject *obj)
4649 int size = obj->vtable->klass->instance_size;
4651 if (obj->vtable->klass->rank)
4652 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4654 o = mono_object_allocate (size, obj->vtable);
4656 if (obj->vtable->klass->has_references) {
4657 mono_gc_wbarrier_object_copy (o, obj);
4659 int size = obj->vtable->klass->instance_size;
4660 /* do not copy the sync state */
4661 mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4663 if (G_UNLIKELY (profile_allocs))
4664 mono_profiler_allocation (o, obj->vtable->klass);
4666 if (obj->vtable->klass->has_finalize)
4667 mono_object_register_finalizer (o);
4672 * mono_array_full_copy:
4673 * @src: source array to copy
4674 * @dest: destination array
4676 * Copies the content of one array to another with exactly the same type and size.
4679 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4682 MonoClass *klass = src->obj.vtable->klass;
4684 MONO_ARCH_SAVE_REGS;
4686 g_assert (klass == dest->obj.vtable->klass);
4688 size = mono_array_length (src);
4689 g_assert (size == mono_array_length (dest));
4690 size *= mono_array_element_size (klass);
4692 if (klass->element_class->valuetype) {
4693 if (klass->element_class->has_references)
4694 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4696 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4698 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4701 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4706 * mono_array_clone_in_domain:
4707 * @domain: the domain in which the array will be cloned into
4708 * @array: the array to clone
4710 * This routine returns a copy of the array that is hosted on the
4711 * specified MonoDomain.
4714 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4719 MonoClass *klass = array->obj.vtable->klass;
4721 MONO_ARCH_SAVE_REGS;
4723 if (array->bounds == NULL) {
4724 size = mono_array_length (array);
4725 o = mono_array_new_full (domain, klass, &size, NULL);
4727 size *= mono_array_element_size (klass);
4729 if (klass->element_class->valuetype) {
4730 if (klass->element_class->has_references)
4731 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4733 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4735 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4738 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4743 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4744 size = mono_array_element_size (klass);
4745 for (i = 0; i < klass->rank; ++i) {
4746 sizes [i] = array->bounds [i].length;
4747 size *= array->bounds [i].length;
4748 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4750 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4752 if (klass->element_class->valuetype) {
4753 if (klass->element_class->has_references)
4754 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4756 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4758 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4761 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4769 * @array: the array to clone
4771 * Returns: A newly created array who is a shallow copy of @array
4774 mono_array_clone (MonoArray *array)
4776 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4779 /* helper macros to check for overflow when calculating the size of arrays */
4780 #ifdef MONO_BIG_ARRAYS
4781 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4782 #define MYGUINT_MAX MYGUINT64_MAX
4783 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4784 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4785 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4786 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4787 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4789 #define MYGUINT32_MAX 4294967295U
4790 #define MYGUINT_MAX MYGUINT32_MAX
4791 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4792 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4793 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4794 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4795 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4799 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4803 byte_len = mono_array_element_size (class);
4804 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4807 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4809 byte_len += sizeof (MonoArray);
4817 * mono_array_new_full:
4818 * @domain: domain where the object is created
4819 * @array_class: array class
4820 * @lengths: lengths for each dimension in the array
4821 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4823 * This routine creates a new array objects with the given dimensions,
4824 * lower bounds and type.
4827 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4829 uintptr_t byte_len = 0, len, bounds_size;
4832 MonoArrayBounds *bounds;
4836 if (!array_class->inited)
4837 mono_class_init (array_class);
4841 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4842 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4844 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4848 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4850 for (i = 0; i < array_class->rank; ++i) {
4851 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4853 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4854 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4859 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4860 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4864 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4865 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4866 byte_len = (byte_len + 3) & ~3;
4867 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4868 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4869 byte_len += bounds_size;
4872 * Following three lines almost taken from mono_object_new ():
4873 * they need to be kept in sync.
4875 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4876 #ifndef HAVE_SGEN_GC
4877 if (!array_class->has_references) {
4878 o = mono_object_allocate_ptrfree (byte_len, vtable);
4879 #if NEED_TO_ZERO_PTRFREE
4880 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4882 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4883 o = mono_object_allocate_spec (byte_len, vtable);
4885 o = mono_object_allocate (byte_len, vtable);
4888 array = (MonoArray*)o;
4889 array->max_length = len;
4892 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4893 array->bounds = bounds;
4897 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4899 o = mono_gc_alloc_vector (vtable, byte_len, len);
4900 array = (MonoArray*)o;
4902 bounds = array->bounds;
4906 for (i = 0; i < array_class->rank; ++i) {
4907 bounds [i].length = lengths [i];
4909 bounds [i].lower_bound = lower_bounds [i];
4913 if (G_UNLIKELY (profile_allocs))
4914 mono_profiler_allocation (o, array_class);
4921 * @domain: domain where the object is created
4922 * @eclass: element class
4923 * @n: number of array elements
4925 * This routine creates a new szarray with @n elements of type @eclass.
4928 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4932 MONO_ARCH_SAVE_REGS;
4934 ac = mono_array_class_get (eclass, 1);
4937 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4941 * mono_array_new_specific:
4942 * @vtable: a vtable in the appropriate domain for an initialized class
4943 * @n: number of array elements
4945 * This routine is a fast alternative to mono_array_new() for code which
4946 * can be sure about the domain it operates in.
4949 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4955 MONO_ARCH_SAVE_REGS;
4957 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4962 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4963 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4966 #ifndef HAVE_SGEN_GC
4967 if (!vtable->klass->has_references) {
4968 o = mono_object_allocate_ptrfree (byte_len, vtable);
4969 #if NEED_TO_ZERO_PTRFREE
4970 ((MonoArray*)o)->bounds = NULL;
4971 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4973 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4974 o = mono_object_allocate_spec (byte_len, vtable);
4976 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4977 o = mono_object_allocate (byte_len, vtable);
4980 ao = (MonoArray *)o;
4983 o = mono_gc_alloc_vector (vtable, byte_len, n);
4987 if (G_UNLIKELY (profile_allocs))
4988 mono_profiler_allocation (o, vtable->klass);
4994 * mono_string_new_utf16:
4995 * @text: a pointer to an utf16 string
4996 * @len: the length of the string
4998 * Returns: A newly created string object which contains @text.
5001 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5005 s = mono_string_new_size (domain, len);
5006 g_assert (s != NULL);
5008 memcpy (mono_string_chars (s), text, len * 2);
5014 * mono_string_new_utf32:
5015 * @text: a pointer to an utf32 string
5016 * @len: the length of the string
5018 * Returns: A newly created string object which contains @text.
5021 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5024 mono_unichar2 *utf16_output = NULL;
5025 gint32 utf16_len = 0;
5026 GError *error = NULL;
5027 glong items_written;
5029 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5032 g_error_free (error);
5034 while (utf16_output [utf16_len]) utf16_len++;
5036 s = mono_string_new_size (domain, utf16_len);
5037 g_assert (s != NULL);
5039 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5041 g_free (utf16_output);
5047 * mono_string_new_size:
5048 * @text: a pointer to an utf16 string
5049 * @len: the length of the string
5051 * Returns: A newly created string object of @len
5054 mono_string_new_size (MonoDomain *domain, gint32 len)
5060 /* check for overflow */
5061 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 2) / 2))
5062 mono_gc_out_of_memory (-1);
5064 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5065 g_assert (size > 0);
5067 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5070 #ifndef HAVE_SGEN_GC
5071 s = mono_object_allocate_ptrfree (size, vtable);
5075 s = mono_gc_alloc_string (vtable, size, len);
5077 #if NEED_TO_ZERO_PTRFREE
5080 if (G_UNLIKELY (profile_allocs))
5081 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5087 * mono_string_new_len:
5088 * @text: a pointer to an utf8 string
5089 * @length: number of bytes in @text to consider
5091 * Returns: A newly created string object which contains @text.
5094 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5096 GError *error = NULL;
5097 MonoString *o = NULL;
5099 glong items_written;
5101 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5104 o = mono_string_new_utf16 (domain, ut, items_written);
5106 g_error_free (error);
5115 * @text: a pointer to an utf8 string
5117 * Returns: A newly created string object which contains @text.
5120 mono_string_new (MonoDomain *domain, const char *text)
5122 GError *error = NULL;
5123 MonoString *o = NULL;
5125 glong items_written;
5130 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5133 o = mono_string_new_utf16 (domain, ut, items_written);
5135 g_error_free (error);
5138 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5143 MonoString *o = NULL;
5145 if (!g_utf8_validate (text, -1, &end))
5148 len = g_utf8_strlen (text, -1);
5149 o = mono_string_new_size (domain, len);
5150 str = mono_string_chars (o);
5152 while (text < end) {
5153 *str++ = g_utf8_get_char (text);
5154 text = g_utf8_next_char (text);
5161 * mono_string_new_wrapper:
5162 * @text: pointer to utf8 characters.
5164 * Helper function to create a string object from @text in the current domain.
5167 mono_string_new_wrapper (const char *text)
5169 MonoDomain *domain = mono_domain_get ();
5171 MONO_ARCH_SAVE_REGS;
5174 return mono_string_new (domain, text);
5181 * @class: the class of the value
5182 * @value: a pointer to the unboxed data
5184 * Returns: A newly created object which contains @value.
5187 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5193 g_assert (class->valuetype);
5194 if (mono_class_is_nullable (class))
5195 return mono_nullable_box (value, class);
5197 vtable = mono_class_vtable (domain, class);
5200 size = mono_class_instance_size (class);
5201 res = mono_object_new_alloc_specific (vtable);
5202 if (G_UNLIKELY (profile_allocs))
5203 mono_profiler_allocation (res, class);
5205 size = size - sizeof (MonoObject);
5208 g_assert (size == mono_class_value_size (class, NULL));
5209 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5211 #if NO_UNALIGNED_ACCESS
5212 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5216 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5219 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5222 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5225 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5228 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5232 if (class->has_finalize)
5233 mono_object_register_finalizer (res);
5239 * @dest: destination pointer
5240 * @src: source pointer
5241 * @klass: a valuetype class
5243 * Copy a valuetype from @src to @dest. This function must be used
5244 * when @klass contains references fields.
5247 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5249 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5253 * mono_value_copy_array:
5254 * @dest: destination array
5255 * @dest_idx: index in the @dest array
5256 * @src: source pointer
5257 * @count: number of items
5259 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5260 * This function must be used when @klass contains references fields.
5261 * Overlap is handled.
5264 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5266 int size = mono_array_element_size (dest->obj.vtable->klass);
5267 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5268 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5269 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5273 * mono_object_get_domain:
5274 * @obj: object to query
5276 * Returns: the MonoDomain where the object is hosted
5279 mono_object_get_domain (MonoObject *obj)
5281 return mono_object_domain (obj);
5285 * mono_object_get_class:
5286 * @obj: object to query
5288 * Returns: the MonOClass of the object.
5291 mono_object_get_class (MonoObject *obj)
5293 return mono_object_class (obj);
5296 * mono_object_get_size:
5297 * @o: object to query
5299 * Returns: the size, in bytes, of @o
5302 mono_object_get_size (MonoObject* o)
5304 MonoClass* klass = mono_object_class (o);
5305 if (klass == mono_defaults.string_class) {
5306 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5307 } else if (o->vtable->rank) {
5308 MonoArray *array = (MonoArray*)o;
5309 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5310 if (array->bounds) {
5313 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5317 return mono_class_instance_size (klass);
5322 * mono_object_unbox:
5323 * @obj: object to unbox
5325 * Returns: a pointer to the start of the valuetype boxed in this
5328 * This method will assert if the object passed is not a valuetype.
5331 mono_object_unbox (MonoObject *obj)
5333 /* add assert for valuetypes? */
5334 g_assert (obj->vtable->klass->valuetype);
5335 return ((char*)obj) + sizeof (MonoObject);
5339 * mono_object_isinst:
5341 * @klass: a pointer to a class
5343 * Returns: @obj if @obj is derived from @klass
5346 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5349 mono_class_init (klass);
5351 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5352 return mono_object_isinst_mbyref (obj, klass);
5357 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5361 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5370 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5371 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5375 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5376 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5379 MonoClass *oklass = vt->klass;
5380 if (mono_class_is_transparent_proxy (oklass))
5381 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5383 mono_class_setup_supertypes (klass);
5384 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5387 #ifndef DISABLE_REMOTING
5388 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5390 MonoDomain *domain = mono_domain_get ();
5392 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5393 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5394 MonoMethod *im = NULL;
5397 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5398 im = mono_object_get_virtual_method (rp, im);
5401 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5404 res = mono_runtime_invoke (im, rp, pa, NULL);
5406 if (*(MonoBoolean *) mono_object_unbox(res)) {
5407 /* Update the vtable of the remote type, so it can safely cast to this new type */
5408 mono_upgrade_remote_class (domain, obj, klass);
5412 #endif /* DISABLE_REMOTING */
5417 * mono_object_castclass_mbyref:
5419 * @klass: a pointer to a class
5421 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5424 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5426 if (!obj) return NULL;
5427 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5429 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5431 "InvalidCastException"));
5436 MonoDomain *orig_domain;
5442 str_lookup (MonoDomain *domain, gpointer user_data)
5444 LDStrInfo *info = user_data;
5445 if (info->res || domain == info->orig_domain)
5447 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5453 mono_string_get_pinned (MonoString *str)
5457 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5458 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5460 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5461 news->length = mono_string_length (str);
5467 #define mono_string_get_pinned(str) (str)
5471 mono_string_is_interned_lookup (MonoString *str, int insert)
5473 MonoGHashTable *ldstr_table;
5477 domain = ((MonoObject *)str)->vtable->domain;
5478 ldstr_table = domain->ldstr_table;
5480 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5485 str = mono_string_get_pinned (str);
5487 mono_g_hash_table_insert (ldstr_table, str, str);
5491 LDStrInfo ldstr_info;
5492 ldstr_info.orig_domain = domain;
5493 ldstr_info.ins = str;
5494 ldstr_info.res = NULL;
5496 mono_domain_foreach (str_lookup, &ldstr_info);
5497 if (ldstr_info.res) {
5499 * the string was already interned in some other domain:
5500 * intern it in the current one as well.
5502 mono_g_hash_table_insert (ldstr_table, str, str);
5512 * mono_string_is_interned:
5513 * @o: String to probe
5515 * Returns whether the string has been interned.
5518 mono_string_is_interned (MonoString *o)
5520 return mono_string_is_interned_lookup (o, FALSE);
5524 * mono_string_intern:
5525 * @o: String to intern
5527 * Interns the string passed.
5528 * Returns: The interned string.
5531 mono_string_intern (MonoString *str)
5533 return mono_string_is_interned_lookup (str, TRUE);
5538 * @domain: the domain where the string will be used.
5539 * @image: a metadata context
5540 * @idx: index into the user string table.
5542 * Implementation for the ldstr opcode.
5543 * Returns: a loaded string from the @image/@idx combination.
5546 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5548 MONO_ARCH_SAVE_REGS;
5550 if (image->dynamic) {
5551 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5554 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5555 return NULL; /*FIXME we should probably be raising an exception here*/
5556 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5561 * mono_ldstr_metadata_sig
5562 * @domain: the domain for the string
5563 * @sig: the signature of a metadata string
5565 * Returns: a MonoString for a string stored in the metadata
5568 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5570 const char *str = sig;
5571 MonoString *o, *interned;
5574 len2 = mono_metadata_decode_blob_size (str, &str);
5577 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5578 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5581 guint16 *p2 = (guint16*)mono_string_chars (o);
5582 for (i = 0; i < len2; ++i) {
5583 *p2 = GUINT16_FROM_LE (*p2);
5589 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5591 /* o will get garbage collected */
5595 o = mono_string_get_pinned (o);
5597 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5604 * mono_string_to_utf8:
5605 * @s: a System.String
5607 * Returns the UTF8 representation for @s.
5608 * The resulting buffer needs to be freed with mono_free().
5610 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5613 mono_string_to_utf8 (MonoString *s)
5616 char *result = mono_string_to_utf8_checked (s, &error);
5618 if (!mono_error_ok (&error))
5619 mono_error_raise_exception (&error);
5624 * mono_string_to_utf8_checked:
5625 * @s: a System.String
5626 * @error: a MonoError.
5628 * Converts a MonoString to its UTF8 representation. May fail; check
5629 * @error to determine whether the conversion was successful.
5630 * The resulting buffer should be freed with mono_free().
5633 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5637 GError *gerror = NULL;
5639 mono_error_init (error);
5645 return g_strdup ("");
5647 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5649 mono_error_set_argument (error, "string", "%s", gerror->message);
5650 g_error_free (gerror);
5653 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5654 if (s->length > written) {
5655 /* allocate the total length and copy the part of the string that has been converted */
5656 char *as2 = g_malloc0 (s->length);
5657 memcpy (as2, as, written);
5666 * mono_string_to_utf8_ignore:
5669 * Converts a MonoString to its UTF8 representation. Will ignore
5670 * invalid surrogate pairs.
5671 * The resulting buffer should be freed with mono_free().
5675 mono_string_to_utf8_ignore (MonoString *s)
5684 return g_strdup ("");
5686 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5688 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5689 if (s->length > written) {
5690 /* allocate the total length and copy the part of the string that has been converted */
5691 char *as2 = g_malloc0 (s->length);
5692 memcpy (as2, as, written);
5701 * mono_string_to_utf8_image_ignore:
5702 * @s: a System.String
5704 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5707 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5709 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5713 * mono_string_to_utf8_mp_ignore:
5714 * @s: a System.String
5716 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5719 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5721 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5726 * mono_string_to_utf16:
5729 * Return an null-terminated array of the utf-16 chars
5730 * contained in @s. The result must be freed with g_free().
5731 * This is a temporary helper until our string implementation
5732 * is reworked to always include the null terminating char.
5735 mono_string_to_utf16 (MonoString *s)
5742 as = g_malloc ((s->length * 2) + 2);
5743 as [(s->length * 2)] = '\0';
5744 as [(s->length * 2) + 1] = '\0';
5747 return (gunichar2 *)(as);
5750 memcpy (as, mono_string_chars(s), s->length * 2);
5751 return (gunichar2 *)(as);
5755 * mono_string_to_utf32:
5758 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5759 * contained in @s. The result must be freed with g_free().
5762 mono_string_to_utf32 (MonoString *s)
5764 mono_unichar4 *utf32_output = NULL;
5765 GError *error = NULL;
5766 glong items_written;
5771 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5774 g_error_free (error);
5776 return utf32_output;
5780 * mono_string_from_utf16:
5781 * @data: the UTF16 string (LPWSTR) to convert
5783 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5785 * Returns: a MonoString.
5788 mono_string_from_utf16 (gunichar2 *data)
5790 MonoDomain *domain = mono_domain_get ();
5796 while (data [len]) len++;
5798 return mono_string_new_utf16 (domain, data, len);
5802 * mono_string_from_utf32:
5803 * @data: the UTF32 string (LPWSTR) to convert
5805 * Converts a UTF32 (UCS-4)to a MonoString.
5807 * Returns: a MonoString.
5810 mono_string_from_utf32 (mono_unichar4 *data)
5812 MonoString* result = NULL;
5813 mono_unichar2 *utf16_output = NULL;
5814 GError *error = NULL;
5815 glong items_written;
5821 while (data [len]) len++;
5823 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5826 g_error_free (error);
5828 result = mono_string_from_utf16 (utf16_output);
5829 g_free (utf16_output);
5834 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5841 r = mono_string_to_utf8_ignore (s);
5843 r = mono_string_to_utf8_checked (s, error);
5844 if (!mono_error_ok (error))
5851 len = strlen (r) + 1;
5853 mp_s = mono_mempool_alloc (mp, len);
5855 mp_s = mono_image_alloc (image, len);
5857 memcpy (mp_s, r, len);
5865 * mono_string_to_utf8_image:
5866 * @s: a System.String
5868 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5871 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5873 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5877 * mono_string_to_utf8_mp:
5878 * @s: a System.String
5880 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5883 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5885 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5889 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5892 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5894 eh_callbacks = *cbs;
5897 MonoRuntimeExceptionHandlingCallbacks *
5898 mono_get_eh_callbacks (void)
5900 return &eh_callbacks;
5904 * mono_raise_exception:
5905 * @ex: exception object
5907 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5910 mono_raise_exception (MonoException *ex)
5913 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5914 * that will cause gcc to omit the function epilog, causing problems when
5915 * the JIT tries to walk the stack, since the return address on the stack
5916 * will point into the next function in the executable, not this one.
5918 eh_callbacks.mono_raise_exception (ex);
5922 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5924 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5928 * mono_wait_handle_new:
5929 * @domain: Domain where the object will be created
5930 * @handle: Handle for the wait handle
5932 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5935 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5937 MonoWaitHandle *res;
5938 gpointer params [1];
5939 static MonoMethod *handle_set;
5941 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5943 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5945 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5947 params [0] = &handle;
5948 mono_runtime_invoke (handle_set, res, params, NULL);
5954 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5956 static MonoClassField *f_os_handle;
5957 static MonoClassField *f_safe_handle;
5959 if (!f_os_handle && !f_safe_handle) {
5960 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5961 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5966 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5970 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5977 mono_runtime_capture_context (MonoDomain *domain)
5979 RuntimeInvokeFunction runtime_invoke;
5981 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5982 MonoMethod *method = mono_get_context_capture_method ();
5983 MonoMethod *wrapper;
5986 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5987 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5988 domain->capture_context_method = mono_compile_method (method);
5991 runtime_invoke = domain->capture_context_runtime_invoke;
5993 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5996 * mono_async_result_new:
5997 * @domain:domain where the object will be created.
5998 * @handle: wait handle.
5999 * @state: state to pass to AsyncResult
6000 * @data: C closure data.
6002 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6003 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6007 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6009 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6010 MonoObject *context = mono_runtime_capture_context (domain);
6011 /* we must capture the execution context from the original thread */
6013 MONO_OBJECT_SETREF (res, execution_context, context);
6014 /* note: result may be null if the flow is suppressed */
6018 MONO_OBJECT_SETREF (res, object_data, object_data);
6019 MONO_OBJECT_SETREF (res, async_state, state);
6021 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6023 res->sync_completed = FALSE;
6024 res->completed = FALSE;
6030 mono_message_init (MonoDomain *domain,
6031 MonoMethodMessage *this,
6032 MonoReflectionMethod *method,
6033 MonoArray *out_args)
6035 static MonoClass *object_array_klass;
6036 static MonoClass *byte_array_klass;
6037 static MonoClass *string_array_klass;
6038 MonoMethodSignature *sig = mono_method_signature (method->method);
6044 if (!object_array_klass) {
6047 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6049 byte_array_klass = klass;
6051 klass = mono_array_class_get (mono_defaults.string_class, 1);
6053 string_array_klass = klass;
6055 klass = mono_array_class_get (mono_defaults.object_class, 1);
6058 mono_atomic_store_release (&object_array_klass, klass);
6061 MONO_OBJECT_SETREF (this, method, method);
6063 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6064 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6065 this->async_result = NULL;
6066 this->call_type = CallType_Sync;
6068 names = g_new (char *, sig->param_count);
6069 mono_method_get_param_names (method->method, (const char **) names);
6070 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6072 for (i = 0; i < sig->param_count; i++) {
6073 name = mono_string_new (domain, names [i]);
6074 mono_array_setref (this->names, i, name);
6078 for (i = 0, j = 0; i < sig->param_count; i++) {
6079 if (sig->params [i]->byref) {
6081 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6082 mono_array_setref (this->args, i, arg);
6086 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6090 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6093 mono_array_set (this->arg_types, guint8, i, arg_type);
6097 #ifndef DISABLE_REMOTING
6099 * mono_remoting_invoke:
6100 * @real_proxy: pointer to a RealProxy object
6101 * @msg: The MonoMethodMessage to execute
6102 * @exc: used to store exceptions
6103 * @out_args: used to store output arguments
6105 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6106 * IMessage interface and it is not trivial to extract results from there. So
6107 * we call an helper method PrivateInvoke instead of calling
6108 * RealProxy::Invoke() directly.
6110 * Returns: the result object.
6113 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6114 MonoObject **exc, MonoArray **out_args)
6116 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6119 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6122 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6124 real_proxy->vtable->domain->private_invoke_method = im;
6127 pa [0] = real_proxy;
6132 return mono_runtime_invoke (im, NULL, pa, exc);
6137 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6138 MonoObject **exc, MonoArray **out_args)
6140 static MonoClass *object_array_klass;
6143 MonoMethodSignature *sig;
6145 int i, j, outarg_count = 0;
6147 #ifndef DISABLE_REMOTING
6148 if (target && mono_object_is_transparent_proxy (target)) {
6149 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6150 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6151 target = tp->rp->unwrapped_server;
6153 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6158 domain = mono_domain_get ();
6159 method = msg->method->method;
6160 sig = mono_method_signature (method);
6162 for (i = 0; i < sig->param_count; i++) {
6163 if (sig->params [i]->byref)
6167 if (!object_array_klass) {
6170 klass = mono_array_class_get (mono_defaults.object_class, 1);
6173 mono_memory_barrier ();
6174 object_array_klass = klass;
6177 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6178 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6181 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6183 for (i = 0, j = 0; i < sig->param_count; i++) {
6184 if (sig->params [i]->byref) {
6186 arg = mono_array_get (msg->args, gpointer, i);
6187 mono_array_setref (*out_args, j, arg);
6196 * mono_object_to_string:
6198 * @exc: Any exception thrown by ToString (). May be NULL.
6200 * Returns: the result of calling ToString () on an object.
6203 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6205 static MonoMethod *to_string = NULL;
6212 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6214 method = mono_object_get_virtual_method (obj, to_string);
6216 // Unbox value type if needed
6217 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6218 target = mono_object_unbox (obj);
6221 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6225 * mono_print_unhandled_exception:
6226 * @exc: The exception
6228 * Prints the unhandled exception.
6231 mono_print_unhandled_exception (MonoObject *exc)
6234 char *message = (char*)"";
6235 gboolean free_message = FALSE;
6238 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6239 message = g_strdup ("OutOfMemoryException");
6240 free_message = TRUE;
6243 if (((MonoException*)exc)->native_trace_ips) {
6244 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6245 free_message = TRUE;
6247 MonoObject *other_exc = NULL;
6248 str = mono_object_to_string (exc, &other_exc);
6250 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6251 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6253 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6254 original_backtrace, nested_backtrace);
6256 g_free (original_backtrace);
6257 g_free (nested_backtrace);
6258 free_message = TRUE;
6260 message = mono_string_to_utf8_checked (str, &error);
6261 if (!mono_error_ok (&error)) {
6262 mono_error_cleanup (&error);
6263 message = (char *) "";
6265 free_message = TRUE;
6272 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6273 * exc->vtable->klass->name, message);
6275 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6282 * mono_delegate_ctor:
6283 * @this: pointer to an uninitialized delegate object
6284 * @target: target object
6285 * @addr: pointer to native code
6288 * Initialize a delegate and sets a specific method, not the one
6289 * associated with addr. This is useful when sharing generic code.
6290 * In that case addr will most probably not be associated with the
6291 * correct instantiation of the method.
6294 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6296 MonoDelegate *delegate = (MonoDelegate *)this;
6303 delegate->method = method;
6305 class = this->vtable->klass;
6306 mono_stats.delegate_creations++;
6308 #ifndef DISABLE_REMOTING
6309 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6311 method = mono_marshal_get_remoting_invoke (method);
6312 delegate->method_ptr = mono_compile_method (method);
6313 MONO_OBJECT_SETREF (delegate, target, target);
6317 delegate->method_ptr = addr;
6318 MONO_OBJECT_SETREF (delegate, target, target);
6321 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6325 * mono_delegate_ctor:
6326 * @this: pointer to an uninitialized delegate object
6327 * @target: target object
6328 * @addr: pointer to native code
6330 * This is used to initialize a delegate.
6333 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6335 MonoDomain *domain = mono_domain_get ();
6337 MonoMethod *method = NULL;
6341 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6343 if (!ji && domain != mono_get_root_domain ())
6344 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6346 method = mono_jit_info_get_method (ji);
6347 g_assert (!method->klass->generic_container);
6350 mono_delegate_ctor_with_method (this, target, addr, method);
6354 * mono_method_call_message_new:
6355 * @method: method to encapsulate
6356 * @params: parameters to the method
6357 * @invoke: optional, delegate invoke.
6358 * @cb: async callback delegate.
6359 * @state: state passed to the async callback.
6361 * Translates arguments pointers into a MonoMethodMessage.
6364 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6365 MonoDelegate **cb, MonoObject **state)
6367 MonoDomain *domain = mono_domain_get ();
6368 MonoMethodSignature *sig = mono_method_signature (method);
6369 MonoMethodMessage *msg;
6372 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6375 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6376 count = sig->param_count - 2;
6378 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6379 count = sig->param_count;
6382 for (i = 0; i < count; i++) {
6387 if (sig->params [i]->byref)
6388 vpos = *((gpointer *)params [i]);
6392 type = sig->params [i]->type;
6393 class = mono_class_from_mono_type (sig->params [i]);
6395 if (class->valuetype)
6396 arg = mono_value_box (domain, class, vpos);
6398 arg = *((MonoObject **)vpos);
6400 mono_array_setref (msg->args, i, arg);
6403 if (cb != NULL && state != NULL) {
6404 *cb = *((MonoDelegate **)params [i]);
6406 *state = *((MonoObject **)params [i]);
6413 * mono_method_return_message_restore:
6415 * Restore results from message based processing back to arguments pointers
6418 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6420 MonoMethodSignature *sig = mono_method_signature (method);
6421 int i, j, type, size, out_len;
6423 if (out_args == NULL)
6425 out_len = mono_array_length (out_args);
6429 for (i = 0, j = 0; i < sig->param_count; i++) {
6430 MonoType *pt = sig->params [i];
6435 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6437 arg = mono_array_get (out_args, gpointer, j);
6440 g_assert (type != MONO_TYPE_VOID);
6442 if (MONO_TYPE_IS_REFERENCE (pt)) {
6443 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6446 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6447 size = mono_class_value_size (class, NULL);
6448 if (class->has_references)
6449 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6451 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6453 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6454 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6463 #ifndef DISABLE_REMOTING
6466 * mono_load_remote_field:
6467 * @this: pointer to an object
6468 * @klass: klass of the object containing @field
6469 * @field: the field to load
6470 * @res: a storage to store the result
6472 * This method is called by the runtime on attempts to load fields of
6473 * transparent proxy objects. @this points to such TP, @klass is the class of
6474 * the object containing @field. @res is a storage location which can be
6475 * used to store the result.
6477 * Returns: an address pointing to the value of field.
6480 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6482 static MonoMethod *getter = NULL;
6483 MonoDomain *domain = mono_domain_get ();
6484 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6485 MonoClass *field_class;
6486 MonoMethodMessage *msg;
6487 MonoArray *out_args;
6491 g_assert (mono_object_is_transparent_proxy (this));
6492 g_assert (res != NULL);
6494 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6495 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6500 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6504 field_class = mono_class_from_mono_type (field->type);
6506 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6507 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6508 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6510 full_name = mono_type_get_full_name (klass);
6511 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6512 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6515 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6517 if (exc) mono_raise_exception ((MonoException *)exc);
6519 if (mono_array_length (out_args) == 0)
6522 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6524 if (field_class->valuetype) {
6525 return ((char *)*res) + sizeof (MonoObject);
6531 * mono_load_remote_field_new:
6536 * Missing documentation.
6539 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6541 static MonoMethod *getter = NULL;
6542 MonoDomain *domain = mono_domain_get ();
6543 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6544 MonoClass *field_class;
6545 MonoMethodMessage *msg;
6546 MonoArray *out_args;
6547 MonoObject *exc, *res;
6550 g_assert (mono_object_is_transparent_proxy (this));
6552 field_class = mono_class_from_mono_type (field->type);
6554 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6556 if (field_class->valuetype) {
6557 res = mono_object_new (domain, field_class);
6558 val = ((gchar *) res) + sizeof (MonoObject);
6562 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6567 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6571 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6572 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6574 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6576 full_name = mono_type_get_full_name (klass);
6577 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6578 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6581 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6583 if (exc) mono_raise_exception ((MonoException *)exc);
6585 if (mono_array_length (out_args) == 0)
6588 res = mono_array_get (out_args, MonoObject *, 0);
6594 * mono_store_remote_field:
6595 * @this: pointer to an object
6596 * @klass: klass of the object containing @field
6597 * @field: the field to load
6598 * @val: the value/object to store
6600 * This method is called by the runtime on attempts to store fields of
6601 * transparent proxy objects. @this points to such TP, @klass is the class of
6602 * the object containing @field. @val is the new value to store in @field.
6605 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6607 static MonoMethod *setter = NULL;
6608 MonoDomain *domain = mono_domain_get ();
6609 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6610 MonoClass *field_class;
6611 MonoMethodMessage *msg;
6612 MonoArray *out_args;
6617 g_assert (mono_object_is_transparent_proxy (this));
6619 field_class = mono_class_from_mono_type (field->type);
6621 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6622 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6623 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6628 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6632 if (field_class->valuetype)
6633 arg = mono_value_box (domain, field_class, val);
6635 arg = *((MonoObject **)val);
6638 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6639 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6641 full_name = mono_type_get_full_name (klass);
6642 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6643 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6644 mono_array_setref (msg->args, 2, arg);
6647 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6649 if (exc) mono_raise_exception ((MonoException *)exc);
6653 * mono_store_remote_field_new:
6659 * Missing documentation
6662 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6664 static MonoMethod *setter = NULL;
6665 MonoDomain *domain = mono_domain_get ();
6666 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6667 MonoClass *field_class;
6668 MonoMethodMessage *msg;
6669 MonoArray *out_args;
6673 g_assert (mono_object_is_transparent_proxy (this));
6675 field_class = mono_class_from_mono_type (field->type);
6677 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6678 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6679 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6684 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6688 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6689 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6691 full_name = mono_type_get_full_name (klass);
6692 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6693 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6694 mono_array_setref (msg->args, 2, arg);
6697 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6699 if (exc) mono_raise_exception ((MonoException *)exc);
6704 * mono_create_ftnptr:
6706 * Given a function address, create a function descriptor for it.
6707 * This is only needed on some platforms.
6710 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6712 return callbacks.create_ftnptr (domain, addr);
6716 * mono_get_addr_from_ftnptr:
6718 * Given a pointer to a function descriptor, return the function address.
6719 * This is only needed on some platforms.
6722 mono_get_addr_from_ftnptr (gpointer descr)
6724 return callbacks.get_addr_from_ftnptr (descr);
6728 * mono_string_chars:
6731 * Returns a pointer to the UCS16 characters stored in the MonoString
6734 mono_string_chars (MonoString *s)
6740 * mono_string_length:
6743 * Returns the lenght in characters of the string
6746 mono_string_length (MonoString *s)
6752 * mono_array_length:
6753 * @array: a MonoArray*
6755 * Returns the total number of elements in the array. This works for
6756 * both vectors and multidimensional arrays.
6759 mono_array_length (MonoArray *array)
6761 return array->max_length;
6765 * mono_array_addr_with_size:
6766 * @array: a MonoArray*
6767 * @size: size of the array elements
6768 * @idx: index into the array
6770 * Returns the address of the @idx element in the array.
6773 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6775 return ((char*)(array)->vector) + size * idx;