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-internals.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/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-error-internals.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/checked-build.h>
46 #include <mono/utils/mono-threads.h>
47 #include "cominterop.h"
50 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
53 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
56 free_main_args (void);
59 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
62 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
63 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
64 static mono_mutex_t ldstr_section;
67 mono_runtime_object_init (MonoObject *this_obj)
69 MONO_REQ_GC_UNSAFE_MODE;
71 MonoMethod *method = NULL;
72 MonoClass *klass = this_obj->vtable->klass;
74 method = mono_class_get_method_from_name (klass, ".ctor", 0);
76 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
78 if (method->klass->valuetype)
79 this_obj = (MonoObject *)mono_object_unbox (this_obj);
80 mono_runtime_invoke (method, this_obj, NULL, NULL);
83 /* The pseudo algorithm for type initialization from the spec
84 Note it doesn't say anything about domains - only threads.
86 2. If the type is initialized you are done.
87 2.1. If the type is not yet initialized, try to take an
89 2.2. If successful, record this thread as responsible for
90 initializing the type and proceed to step 2.3.
91 2.2.1. If not, see whether this thread or any thread
92 waiting for this thread to complete already holds the lock.
93 2.2.2. If so, return since blocking would create a deadlock. This thread
94 will now see an incompletely initialized state for the type,
95 but no deadlock will arise.
96 2.2.3 If not, block until the type is initialized then return.
97 2.3 Initialize the parent type and then all interfaces implemented
99 2.4 Execute the type initialization code for this type.
100 2.5 Mark the type as initialized, release the initialization lock,
101 awaken any threads waiting for this type to be initialized,
108 MonoNativeThreadId initializing_tid;
109 guint32 waiting_count;
111 MonoCoopMutex initialization_section;
112 } TypeInitializationLock;
114 /* for locking access to type_initialization_hash and blocked_thread_hash */
115 static MonoCoopMutex type_initialization_section;
118 mono_type_initialization_lock (void)
120 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
121 mono_coop_mutex_lock (&type_initialization_section);
125 mono_type_initialization_unlock (void)
127 mono_coop_mutex_unlock (&type_initialization_section);
131 mono_type_init_lock (TypeInitializationLock *lock)
133 MONO_REQ_GC_NEUTRAL_MODE;
135 mono_coop_mutex_lock (&lock->initialization_section);
139 mono_type_init_unlock (TypeInitializationLock *lock)
141 mono_coop_mutex_unlock (&lock->initialization_section);
144 /* from vtable to lock */
145 static GHashTable *type_initialization_hash;
147 /* from thread id to thread id being waited on */
148 static GHashTable *blocked_thread_hash;
151 static MonoThread *main_thread;
153 /* Functions supplied by the runtime */
154 static MonoRuntimeCallbacks callbacks;
157 * mono_thread_set_main:
158 * @thread: thread to set as the main thread
160 * This function can be used to instruct the runtime to treat @thread
161 * as the main thread, ie, the thread that would normally execute the Main()
162 * method. This basically means that at the end of @thread, the runtime will
163 * wait for the existing foreground threads to quit and other such details.
166 mono_thread_set_main (MonoThread *thread)
168 MONO_REQ_GC_UNSAFE_MODE;
170 static gboolean registered = FALSE;
173 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
177 main_thread = thread;
181 mono_thread_get_main (void)
183 MONO_REQ_GC_UNSAFE_MODE;
189 mono_type_initialization_init (void)
191 mono_coop_mutex_init_recursive (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 mono_os_mutex_init_recursive (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 mono_coop_mutex_destroy (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 mono_os_mutex_destroy (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MONO_REQ_GC_UNSAFE_MODE;
225 MonoDomain *domain = vtable->domain;
226 MonoClass *klass = vtable->klass;
230 if (!vtable->init_failed)
231 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
234 * If the initializing thread was rudely aborted, the exception is not stored
238 mono_domain_lock (domain);
239 if (domain->type_init_exception_hash)
240 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
241 mono_domain_unlock (domain);
244 if (klass->name_space && *klass->name_space)
245 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
247 full_name = g_strdup (klass->name);
248 ex = mono_get_exception_type_initialization (full_name, NULL);
255 * mono_runtime_class_init:
256 * @vtable: vtable that needs to be initialized
258 * This routine calls the class constructor for @vtable.
261 mono_runtime_class_init (MonoVTable *vtable)
263 MONO_REQ_GC_UNSAFE_MODE;
265 mono_runtime_class_init_full (vtable, TRUE);
269 * mono_runtime_class_init_full:
270 * @vtable that neeeds to be initialized
271 * @raise_exception is TRUE, exceptions are raised intead of returned
275 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
277 MONO_REQ_GC_UNSAFE_MODE;
280 MonoException *exc_to_throw;
281 MonoMethod *method = NULL;
284 MonoDomain *domain = vtable->domain;
285 TypeInitializationLock *lock;
286 MonoNativeThreadId tid;
287 int do_initialization = 0;
288 MonoDomain *last_domain = NULL;
290 if (vtable->initialized)
294 klass = vtable->klass;
296 if (!klass->image->checked_module_cctor) {
297 mono_image_check_for_module_cctor (klass->image);
298 if (klass->image->has_module_cctor) {
300 MonoClass *module_klass;
301 MonoVTable *module_vtable;
303 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
305 exc = mono_error_convert_to_exception (&error);
307 mono_raise_exception (exc);
311 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
314 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
319 method = mono_class_get_cctor (klass);
321 vtable->initialized = 1;
325 tid = mono_native_thread_id_get ();
327 mono_type_initialization_lock ();
328 /* double check... */
329 if (vtable->initialized) {
330 mono_type_initialization_unlock ();
333 if (vtable->init_failed) {
334 mono_type_initialization_unlock ();
336 /* The type initialization already failed once, rethrow the same exception */
338 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
339 return get_type_init_exception_for_vtable (vtable);
341 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
343 /* This thread will get to do the initialization */
344 if (mono_domain_get () != domain) {
345 /* Transfer into the target domain */
346 last_domain = mono_domain_get ();
347 if (!mono_domain_set (domain, FALSE)) {
348 vtable->initialized = 1;
349 mono_type_initialization_unlock ();
351 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
352 return mono_get_exception_appdomain_unloaded ();
355 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
356 mono_coop_mutex_init_recursive (&lock->initialization_section);
357 lock->initializing_tid = tid;
358 lock->waiting_count = 1;
360 /* grab the vtable lock while this thread still owns type_initialization_section */
361 /* This is why type_initialization_lock needs to enter blocking mode */
362 mono_type_init_lock (lock);
363 g_hash_table_insert (type_initialization_hash, vtable, lock);
364 do_initialization = 1;
367 TypeInitializationLock *pending_lock;
369 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
370 mono_type_initialization_unlock ();
373 /* see if the thread doing the initialization is already blocked on this thread */
374 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
375 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
376 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
377 if (!pending_lock->done) {
378 mono_type_initialization_unlock ();
381 /* the thread doing the initialization is blocked on this thread,
382 but on a lock that has already been freed. It just hasn't got
387 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
389 ++lock->waiting_count;
390 /* record the fact that we are waiting on the initializing thread */
391 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
393 mono_type_initialization_unlock ();
395 if (do_initialization) {
396 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
398 /* If the initialization failed, mark the class as unusable. */
399 /* Avoid infinite loops */
401 (klass->image == mono_defaults.corlib &&
402 !strcmp (klass->name_space, "System") &&
403 !strcmp (klass->name, "TypeInitializationException")))) {
404 vtable->init_failed = 1;
406 if (klass->name_space && *klass->name_space)
407 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
409 full_name = g_strdup (klass->name);
410 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
414 * Store the exception object so it could be thrown on subsequent
417 mono_domain_lock (domain);
418 if (!domain->type_init_exception_hash)
419 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
420 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
421 mono_domain_unlock (domain);
425 mono_domain_set (last_domain, TRUE);
427 mono_type_init_unlock (lock);
429 /* this just blocks until the initializing thread is done */
430 mono_type_init_lock (lock);
431 mono_type_init_unlock (lock);
434 mono_type_initialization_lock ();
435 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
436 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
437 --lock->waiting_count;
438 if (lock->waiting_count == 0) {
439 mono_coop_mutex_destroy (&lock->initialization_section);
440 g_hash_table_remove (type_initialization_hash, vtable);
443 mono_memory_barrier ();
444 if (!vtable->init_failed)
445 vtable->initialized = 1;
446 mono_type_initialization_unlock ();
448 if (vtable->init_failed) {
449 /* Either we were the initializing thread or we waited for the initialization */
451 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
452 return get_type_init_exception_for_vtable (vtable);
458 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
460 MONO_REQ_GC_NEUTRAL_MODE;
462 MonoVTable *vtable = (MonoVTable*)key;
464 TypeInitializationLock *lock = (TypeInitializationLock*) value;
465 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
468 * Have to set this since it cannot be set by the normal code in
469 * mono_runtime_class_init (). In this case, the exception object is not stored,
470 * and get_type_init_exception_for_class () needs to be aware of this.
472 vtable->init_failed = 1;
473 mono_type_init_unlock (lock);
474 --lock->waiting_count;
475 if (lock->waiting_count == 0) {
476 mono_coop_mutex_destroy (&lock->initialization_section);
485 mono_release_type_locks (MonoInternalThread *thread)
487 MONO_REQ_GC_UNSAFE_MODE;
489 mono_type_initialization_lock ();
490 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
491 mono_type_initialization_unlock ();
495 default_trampoline (MonoMethod *method)
501 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
503 g_assert_not_reached ();
508 #ifndef DISABLE_REMOTING
511 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
513 g_error ("remoting not installed");
517 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
521 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
523 g_assert_not_reached ();
527 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
528 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
529 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
530 static MonoImtThunkBuilder imt_thunk_builder;
531 static gboolean always_build_imt_thunks;
533 #if (MONO_IMT_SIZE > 32)
534 #error "MONO_IMT_SIZE cannot be larger than 32"
538 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
540 memcpy (&callbacks, cbs, sizeof (*cbs));
543 MonoRuntimeCallbacks*
544 mono_get_runtime_callbacks (void)
550 mono_install_trampoline (MonoTrampoline func)
552 arch_create_jit_trampoline = func? func: default_trampoline;
556 mono_install_jump_trampoline (MonoJumpTrampoline func)
558 arch_create_jump_trampoline = func? func: default_jump_trampoline;
561 #ifndef DISABLE_REMOTING
563 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
565 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
570 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
572 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
576 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
577 imt_thunk_builder = func;
581 mono_set_always_build_imt_thunks (gboolean value)
583 always_build_imt_thunks = value;
586 static MonoCompileFunc default_mono_compile_method = NULL;
589 * mono_install_compile_method:
590 * @func: function to install
592 * This is a VM internal routine
595 mono_install_compile_method (MonoCompileFunc func)
597 default_mono_compile_method = func;
601 * mono_compile_method:
602 * @method: The method to compile.
604 * This JIT-compiles the method, and returns the pointer to the native code
608 mono_compile_method (MonoMethod *method)
610 MONO_REQ_GC_NEUTRAL_MODE
612 if (!default_mono_compile_method) {
613 g_error ("compile method called on uninitialized runtime");
616 return default_mono_compile_method (method);
620 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
622 MONO_REQ_GC_NEUTRAL_MODE
624 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
628 mono_runtime_create_delegate_trampoline (MonoClass *klass)
630 MONO_REQ_GC_NEUTRAL_MODE
632 return arch_create_delegate_trampoline (mono_domain_get (), klass);
635 static MonoFreeMethodFunc default_mono_free_method = NULL;
638 * mono_install_free_method:
639 * @func: pointer to the MonoFreeMethodFunc used to release a method
641 * This is an internal VM routine, it is used for the engines to
642 * register a handler to release the resources associated with a method.
644 * Methods are freed when no more references to the delegate that holds
648 mono_install_free_method (MonoFreeMethodFunc func)
650 default_mono_free_method = func;
654 * mono_runtime_free_method:
655 * @domain; domain where the method is hosted
656 * @method: method to release
658 * This routine is invoked to free the resources associated with
659 * a method that has been JIT compiled. This is used to discard
660 * methods that were used only temporarily (for example, used in marshalling)
664 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
666 MONO_REQ_GC_NEUTRAL_MODE
668 if (default_mono_free_method != NULL)
669 default_mono_free_method (domain, method);
671 mono_method_clear_object (domain, method);
673 mono_free_method (method);
677 * The vtables in the root appdomain are assumed to be reachable by other
678 * roots, and we don't use typed allocation in the other domains.
681 /* The sync block is no longer a GC pointer */
682 #define GC_HEADER_BITMAP (0)
684 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
687 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
689 MONO_REQ_GC_NEUTRAL_MODE;
691 MonoClassField *field;
697 max_size = mono_class_data_size (klass) / sizeof (gpointer);
699 max_size = klass->instance_size / sizeof (gpointer);
700 if (max_size > size) {
701 g_assert (offset <= 0);
702 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
707 /*An Ephemeron cannot be marked by sgen*/
708 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
710 memset (bitmap, 0, size / 8);
715 for (p = klass; p != NULL; p = p->parent) {
716 gpointer iter = NULL;
717 while ((field = mono_class_get_fields (p, &iter))) {
721 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
723 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
726 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
729 /* FIXME: should not happen, flag as type load error */
730 if (field->type->byref)
733 if (static_fields && field->offset == -1)
737 pos = field->offset / sizeof (gpointer);
740 type = mono_type_get_underlying_type (field->type);
741 switch (type->type) {
744 case MONO_TYPE_FNPTR:
746 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
751 if (klass->image != mono_defaults.corlib)
754 case MONO_TYPE_STRING:
755 case MONO_TYPE_SZARRAY:
756 case MONO_TYPE_CLASS:
757 case MONO_TYPE_OBJECT:
758 case MONO_TYPE_ARRAY:
759 g_assert ((field->offset % sizeof(gpointer)) == 0);
761 g_assert (pos < size || pos <= max_size);
762 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
763 *max_set = MAX (*max_set, pos);
765 case MONO_TYPE_GENERICINST:
766 if (!mono_type_generic_inst_is_valuetype (type)) {
767 g_assert ((field->offset % sizeof(gpointer)) == 0);
769 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
770 *max_set = MAX (*max_set, pos);
775 case MONO_TYPE_VALUETYPE: {
776 MonoClass *fclass = mono_class_from_mono_type (field->type);
777 if (fclass->has_references) {
778 /* remove the object header */
779 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
793 case MONO_TYPE_BOOLEAN:
797 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
808 * mono_class_compute_bitmap:
810 * Mono internal function to compute a bitmap of reference fields in a class.
813 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
815 MONO_REQ_GC_NEUTRAL_MODE;
817 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
822 * similar to the above, but sets the bits in the bitmap for any non-ref field
823 * and ignores static fields
826 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
828 MonoClassField *field;
833 max_size = class->instance_size / sizeof (gpointer);
834 if (max_size >= size) {
835 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
838 for (p = class; p != NULL; p = p->parent) {
839 gpointer iter = NULL;
840 while ((field = mono_class_get_fields (p, &iter))) {
843 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
845 /* FIXME: should not happen, flag as type load error */
846 if (field->type->byref)
849 pos = field->offset / sizeof (gpointer);
852 type = mono_type_get_underlying_type (field->type);
853 switch (type->type) {
854 #if SIZEOF_VOID_P == 8
858 case MONO_TYPE_FNPTR:
863 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
864 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
865 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
868 #if SIZEOF_VOID_P == 4
872 case MONO_TYPE_FNPTR:
877 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
878 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
879 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
885 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
886 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
887 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
890 case MONO_TYPE_BOOLEAN:
893 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
895 case MONO_TYPE_STRING:
896 case MONO_TYPE_SZARRAY:
897 case MONO_TYPE_CLASS:
898 case MONO_TYPE_OBJECT:
899 case MONO_TYPE_ARRAY:
901 case MONO_TYPE_GENERICINST:
902 if (!mono_type_generic_inst_is_valuetype (type)) {
907 case MONO_TYPE_VALUETYPE: {
908 MonoClass *fclass = mono_class_from_mono_type (field->type);
909 /* remove the object header */
910 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
914 g_assert_not_reached ();
923 * mono_class_insecure_overlapping:
924 * check if a class with explicit layout has references and non-references
925 * fields overlapping.
927 * Returns: TRUE if it is insecure to load the type.
930 mono_class_insecure_overlapping (MonoClass *klass)
934 gsize default_bitmap [4] = {0};
936 gsize default_nrbitmap [4] = {0};
937 int i, insecure = FALSE;
940 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
941 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
943 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
944 int idx = i % (sizeof (bitmap [0]) * 8);
945 if (bitmap [idx] & nrbitmap [idx]) {
950 if (bitmap != default_bitmap)
952 if (nrbitmap != default_nrbitmap)
955 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
963 mono_string_alloc (int length)
965 MONO_REQ_GC_UNSAFE_MODE;
966 return mono_string_new_size (mono_domain_get (), length);
970 mono_class_compute_gc_descriptor (MonoClass *klass)
972 MONO_REQ_GC_NEUTRAL_MODE;
976 gsize default_bitmap [4] = {0};
977 static gboolean gcj_inited = FALSE;
982 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
983 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
986 mono_loader_unlock ();
990 mono_class_init (klass);
992 if (klass->gc_descr_inited)
995 klass->gc_descr_inited = TRUE;
996 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
998 bitmap = default_bitmap;
999 if (klass == mono_defaults.string_class) {
1000 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1001 } else if (klass->rank) {
1002 mono_class_compute_gc_descriptor (klass->element_class);
1003 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1005 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1006 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1007 class->name_space, class->name);*/
1009 /* remove the object header */
1010 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1011 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1012 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1013 class->name_space, class->name);*/
1014 if (bitmap != default_bitmap)
1018 /*static int count = 0;
1021 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1022 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1024 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1025 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1027 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1028 if (bitmap != default_bitmap)
1034 * field_is_special_static:
1035 * @fklass: The MonoClass to look up.
1036 * @field: The MonoClassField describing the field.
1038 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1039 * SPECIAL_STATIC_NONE otherwise.
1042 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1044 MONO_REQ_GC_NEUTRAL_MODE;
1046 MonoCustomAttrInfo *ainfo;
1048 ainfo = mono_custom_attrs_from_field (fklass, field);
1051 for (i = 0; i < ainfo->num_attrs; ++i) {
1052 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1053 if (klass->image == mono_defaults.corlib) {
1054 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1055 mono_custom_attrs_free (ainfo);
1056 return SPECIAL_STATIC_THREAD;
1058 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1059 mono_custom_attrs_free (ainfo);
1060 return SPECIAL_STATIC_CONTEXT;
1064 mono_custom_attrs_free (ainfo);
1065 return SPECIAL_STATIC_NONE;
1068 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1069 #define mix(a,b,c) { \
1070 a -= c; a ^= rot(c, 4); c += b; \
1071 b -= a; b ^= rot(a, 6); a += c; \
1072 c -= b; c ^= rot(b, 8); b += a; \
1073 a -= c; a ^= rot(c,16); c += b; \
1074 b -= a; b ^= rot(a,19); a += c; \
1075 c -= b; c ^= rot(b, 4); b += a; \
1077 #define final(a,b,c) { \
1078 c ^= b; c -= rot(b,14); \
1079 a ^= c; a -= rot(c,11); \
1080 b ^= a; b -= rot(a,25); \
1081 c ^= b; c -= rot(b,16); \
1082 a ^= c; a -= rot(c,4); \
1083 b ^= a; b -= rot(a,14); \
1084 c ^= b; c -= rot(b,24); \
1088 * mono_method_get_imt_slot:
1090 * The IMT slot is embedded into AOTed code, so this must return the same value
1091 * for the same method across all executions. This means:
1092 * - pointers shouldn't be used as hash values.
1093 * - mono_metadata_str_hash () should be used for hashing strings.
1096 mono_method_get_imt_slot (MonoMethod *method)
1098 MONO_REQ_GC_NEUTRAL_MODE;
1100 MonoMethodSignature *sig;
1102 guint32 *hashes_start, *hashes;
1106 /* This can be used to stress tests the collision code */
1110 * We do this to simplify generic sharing. It will hurt
1111 * performance in cases where a class implements two different
1112 * instantiations of the same generic interface.
1113 * The code in build_imt_slots () depends on this.
1115 if (method->is_inflated)
1116 method = ((MonoMethodInflated*)method)->declaring;
1118 sig = mono_method_signature (method);
1119 hashes_count = sig->param_count + 4;
1120 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1121 hashes = hashes_start;
1123 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1124 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1125 method->klass->name_space, method->klass->name, method->name);
1128 /* Initialize hashes */
1129 hashes [0] = mono_metadata_str_hash (method->klass->name);
1130 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1131 hashes [2] = mono_metadata_str_hash (method->name);
1132 hashes [3] = mono_metadata_type_hash (sig->ret);
1133 for (i = 0; i < sig->param_count; i++) {
1134 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1137 /* Setup internal state */
1138 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1140 /* Handle most of the hashes */
1141 while (hashes_count > 3) {
1150 /* Handle the last 3 hashes (all the case statements fall through) */
1151 switch (hashes_count) {
1152 case 3 : c += hashes [2];
1153 case 2 : b += hashes [1];
1154 case 1 : a += hashes [0];
1156 case 0: /* nothing left to add */
1160 free (hashes_start);
1161 /* Report the result */
1162 return c % MONO_IMT_SIZE;
1171 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1172 MONO_REQ_GC_NEUTRAL_MODE;
1174 guint32 imt_slot = mono_method_get_imt_slot (method);
1175 MonoImtBuilderEntry *entry;
1177 if (slot_num >= 0 && imt_slot != slot_num) {
1178 /* we build just a single imt slot and this is not it */
1182 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1183 entry->key = method;
1184 entry->value.vtable_slot = vtable_slot;
1185 entry->next = imt_builder [imt_slot];
1186 if (imt_builder [imt_slot] != NULL) {
1187 entry->children = imt_builder [imt_slot]->children + 1;
1188 if (entry->children == 1) {
1189 mono_stats.imt_slots_with_collisions++;
1190 *imt_collisions_bitmap |= (1 << imt_slot);
1193 entry->children = 0;
1194 mono_stats.imt_used_slots++;
1196 imt_builder [imt_slot] = entry;
1199 char *method_name = mono_method_full_name (method, TRUE);
1200 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1201 method, method_name, imt_slot, vtable_slot, entry->children);
1202 g_free (method_name);
1209 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1211 MonoMethod *method = e->key;
1212 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1216 method->klass->name_space,
1217 method->klass->name,
1220 printf (" * %s: NULL\n", message);
1226 compare_imt_builder_entries (const void *p1, const void *p2) {
1227 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1228 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1230 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1234 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1236 MONO_REQ_GC_NEUTRAL_MODE;
1238 int count = end - start;
1239 int chunk_start = out_array->len;
1242 for (i = start; i < end; ++i) {
1243 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1244 item->key = sorted_array [i]->key;
1245 item->value = sorted_array [i]->value;
1246 item->has_target_code = sorted_array [i]->has_target_code;
1247 item->is_equals = TRUE;
1249 item->check_target_idx = out_array->len + 1;
1251 item->check_target_idx = 0;
1252 g_ptr_array_add (out_array, item);
1255 int middle = start + count / 2;
1256 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1258 item->key = sorted_array [middle]->key;
1259 item->is_equals = FALSE;
1260 g_ptr_array_add (out_array, item);
1261 imt_emit_ir (sorted_array, start, middle, out_array);
1262 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1268 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1269 MONO_REQ_GC_NEUTRAL_MODE;
1271 int number_of_entries = entries->children + 1;
1272 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1273 GPtrArray *result = g_ptr_array_new ();
1274 MonoImtBuilderEntry *current_entry;
1277 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1278 sorted_array [i] = current_entry;
1280 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1282 /*for (i = 0; i < number_of_entries; i++) {
1283 print_imt_entry (" sorted array:", sorted_array [i], i);
1286 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1288 free (sorted_array);
1293 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1295 MONO_REQ_GC_NEUTRAL_MODE;
1297 if (imt_builder_entry != NULL) {
1298 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1299 /* No collision, return the vtable slot contents */
1300 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1302 /* Collision, build the thunk */
1303 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1306 result = imt_thunk_builder (vtable, domain,
1307 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1308 for (i = 0; i < imt_ir->len; ++i)
1309 g_free (g_ptr_array_index (imt_ir, i));
1310 g_ptr_array_free (imt_ir, TRUE);
1322 static MonoImtBuilderEntry*
1323 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1326 * LOCKING: requires the loader and domain locks.
1330 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1332 MONO_REQ_GC_NEUTRAL_MODE;
1336 guint32 imt_collisions_bitmap = 0;
1337 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1338 int method_count = 0;
1339 gboolean record_method_count_for_max_collisions = FALSE;
1340 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1343 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1345 for (i = 0; i < klass->interface_offsets_count; ++i) {
1346 MonoClass *iface = klass->interfaces_packed [i];
1347 int interface_offset = klass->interface_offsets_packed [i];
1348 int method_slot_in_interface, vt_slot;
1350 if (mono_class_has_variant_generic_params (iface))
1351 has_variant_iface = TRUE;
1353 mono_class_setup_methods (iface);
1354 vt_slot = interface_offset;
1355 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1358 if (slot_num >= 0 && iface->is_inflated) {
1360 * The imt slot of the method is the same as for its declaring method,
1361 * see the comment in mono_method_get_imt_slot (), so we can
1362 * avoid inflating methods which will be discarded by
1363 * add_imt_builder_entry anyway.
1365 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1366 if (mono_method_get_imt_slot (method) != slot_num) {
1371 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1372 if (method->is_generic) {
1373 has_generic_virtual = TRUE;
1378 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1379 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1384 if (extra_interfaces) {
1385 int interface_offset = klass->vtable_size;
1387 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1388 MonoClass* iface = (MonoClass *)list_item->data;
1389 int method_slot_in_interface;
1390 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1391 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1393 if (method->is_generic)
1394 has_generic_virtual = TRUE;
1395 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1397 interface_offset += iface->method.count;
1400 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1401 /* overwrite the imt slot only if we're building all the entries or if
1402 * we're building this specific one
1404 if (slot_num < 0 || i == slot_num) {
1405 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1408 if (imt_builder [i]) {
1409 MonoImtBuilderEntry *entry;
1411 /* Link entries with imt_builder [i] */
1412 for (entry = entries; entry->next; entry = entry->next) {
1414 MonoMethod *method = (MonoMethod*)entry->key;
1415 char *method_name = mono_method_full_name (method, TRUE);
1416 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1417 g_free (method_name);
1420 entry->next = imt_builder [i];
1421 entries->children += imt_builder [i]->children + 1;
1423 imt_builder [i] = entries;
1426 if (has_generic_virtual || has_variant_iface) {
1428 * There might be collisions later when the the thunk is expanded.
1430 imt_collisions_bitmap |= (1 << i);
1433 * The IMT thunk might be called with an instance of one of the
1434 * generic virtual methods, so has to fallback to the IMT trampoline.
1436 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1438 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1441 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1445 if (imt_builder [i] != NULL) {
1446 int methods_in_slot = imt_builder [i]->children + 1;
1447 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1448 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1449 record_method_count_for_max_collisions = TRUE;
1451 method_count += methods_in_slot;
1455 mono_stats.imt_number_of_methods += method_count;
1456 if (record_method_count_for_max_collisions) {
1457 mono_stats.imt_method_count_when_max_collisions = method_count;
1460 for (i = 0; i < MONO_IMT_SIZE; i++) {
1461 MonoImtBuilderEntry* entry = imt_builder [i];
1462 while (entry != NULL) {
1463 MonoImtBuilderEntry* next = entry->next;
1469 /* we OR the bitmap since we may build just a single imt slot at a time */
1470 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1474 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1475 MONO_REQ_GC_NEUTRAL_MODE;
1477 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1481 * mono_vtable_build_imt_slot:
1482 * @vtable: virtual object table struct
1483 * @imt_slot: slot in the IMT table
1485 * Fill the given @imt_slot in the IMT table of @vtable with
1486 * a trampoline or a thunk for the case of collisions.
1487 * This is part of the internal mono API.
1489 * LOCKING: Take the domain lock.
1492 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1494 MONO_REQ_GC_NEUTRAL_MODE;
1496 gpointer *imt = (gpointer*)vtable;
1497 imt -= MONO_IMT_SIZE;
1498 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1500 /* no support for extra interfaces: the proxy objects will need
1501 * to build the complete IMT
1502 * Update and heck needs to ahppen inside the proper domain lock, as all
1503 * the changes made to a MonoVTable.
1505 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1506 mono_domain_lock (vtable->domain);
1507 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1508 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1509 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1510 mono_domain_unlock (vtable->domain);
1511 mono_loader_unlock ();
1516 * The first two free list entries both belong to the wait list: The
1517 * first entry is the pointer to the head of the list and the second
1518 * entry points to the last element. That way appending and removing
1519 * the first element are both O(1) operations.
1521 #ifdef MONO_SMALL_CONFIG
1522 #define NUM_FREE_LISTS 6
1524 #define NUM_FREE_LISTS 12
1526 #define FIRST_FREE_LIST_SIZE 64
1527 #define MAX_WAIT_LENGTH 50
1528 #define THUNK_THRESHOLD 10
1531 * LOCKING: The domain lock must be held.
1534 init_thunk_free_lists (MonoDomain *domain)
1536 MONO_REQ_GC_NEUTRAL_MODE;
1538 if (domain->thunk_free_lists)
1540 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1544 list_index_for_size (int item_size)
1547 int size = FIRST_FREE_LIST_SIZE;
1549 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1558 * mono_method_alloc_generic_virtual_thunk:
1560 * @size: size in bytes
1562 * Allocs size bytes to be used for the code of a generic virtual
1563 * thunk. It's either allocated from the domain's code manager or
1564 * reused from a previously invalidated piece.
1566 * LOCKING: The domain lock must be held.
1569 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1571 MONO_REQ_GC_NEUTRAL_MODE;
1573 static gboolean inited = FALSE;
1574 static int generic_virtual_thunks_size = 0;
1578 MonoThunkFreeList **l;
1580 init_thunk_free_lists (domain);
1582 size += sizeof (guint32);
1583 if (size < sizeof (MonoThunkFreeList))
1584 size = sizeof (MonoThunkFreeList);
1586 i = list_index_for_size (size);
1587 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1588 if ((*l)->size >= size) {
1589 MonoThunkFreeList *item = *l;
1591 return ((guint32*)item) + 1;
1595 /* no suitable item found - search lists of larger sizes */
1596 while (++i < NUM_FREE_LISTS) {
1597 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1600 g_assert (item->size > size);
1601 domain->thunk_free_lists [i] = item->next;
1602 return ((guint32*)item) + 1;
1605 /* still nothing found - allocate it */
1607 mono_counters_register ("Generic virtual thunk bytes",
1608 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1611 generic_virtual_thunks_size += size;
1613 p = (guint32 *)mono_domain_code_reserve (domain, size);
1616 mono_domain_lock (domain);
1617 if (!domain->generic_virtual_thunks)
1618 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1619 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1620 mono_domain_unlock (domain);
1626 * LOCKING: The domain lock must be held.
1629 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1631 MONO_REQ_GC_NEUTRAL_MODE;
1633 guint32 *p = (guint32 *)code;
1634 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1635 gboolean found = FALSE;
1637 mono_domain_lock (domain);
1638 if (!domain->generic_virtual_thunks)
1639 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1640 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1642 mono_domain_unlock (domain);
1645 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1647 init_thunk_free_lists (domain);
1649 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1650 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1651 int length = item->length;
1654 /* unlink the first item from the wait list */
1655 domain->thunk_free_lists [0] = item->next;
1656 domain->thunk_free_lists [0]->length = length - 1;
1658 i = list_index_for_size (item->size);
1660 /* put it in the free list */
1661 item->next = domain->thunk_free_lists [i];
1662 domain->thunk_free_lists [i] = item;
1666 if (domain->thunk_free_lists [1]) {
1667 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1668 domain->thunk_free_lists [0]->length++;
1670 g_assert (!domain->thunk_free_lists [0]);
1672 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1673 domain->thunk_free_lists [0]->length = 1;
1677 typedef struct _GenericVirtualCase {
1681 struct _GenericVirtualCase *next;
1682 } GenericVirtualCase;
1685 * get_generic_virtual_entries:
1687 * Return IMT entries for the generic virtual method instances and
1688 * variant interface methods for vtable slot
1691 static MonoImtBuilderEntry*
1692 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1694 MONO_REQ_GC_NEUTRAL_MODE;
1696 GenericVirtualCase *list;
1697 MonoImtBuilderEntry *entries;
1699 mono_domain_lock (domain);
1700 if (!domain->generic_virtual_cases)
1701 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1703 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1706 for (; list; list = list->next) {
1707 MonoImtBuilderEntry *entry;
1709 if (list->count < THUNK_THRESHOLD)
1712 entry = g_new0 (MonoImtBuilderEntry, 1);
1713 entry->key = list->method;
1714 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1715 entry->has_target_code = 1;
1717 entry->children = entries->children + 1;
1718 entry->next = entries;
1722 mono_domain_unlock (domain);
1724 /* FIXME: Leaking memory ? */
1729 * mono_method_add_generic_virtual_invocation:
1731 * @vtable_slot: pointer to the vtable slot
1732 * @method: the inflated generic virtual method
1733 * @code: the method's code
1735 * Registers a call via unmanaged code to a generic virtual method
1736 * instantiation or variant interface method. If the number of calls reaches a threshold
1737 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1738 * virtual method thunk.
1741 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1742 gpointer *vtable_slot,
1743 MonoMethod *method, gpointer code)
1745 MONO_REQ_GC_NEUTRAL_MODE;
1747 static gboolean inited = FALSE;
1748 static int num_added = 0;
1750 GenericVirtualCase *gvc, *list;
1751 MonoImtBuilderEntry *entries;
1755 mono_domain_lock (domain);
1756 if (!domain->generic_virtual_cases)
1757 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1759 /* Check whether the case was already added */
1760 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1763 if (gvc->method == method)
1768 /* If not found, make a new one */
1770 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1771 gvc->method = method;
1774 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1776 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1779 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1785 if (++gvc->count == THUNK_THRESHOLD) {
1786 gpointer *old_thunk = (void **)*vtable_slot;
1787 gpointer vtable_trampoline = NULL;
1788 gpointer imt_trampoline = NULL;
1790 if ((gpointer)vtable_slot < (gpointer)vtable) {
1791 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1792 int imt_slot = MONO_IMT_SIZE + displacement;
1794 /* Force the rebuild of the thunk at the next call */
1795 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1796 *vtable_slot = imt_trampoline;
1798 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1800 entries = get_generic_virtual_entries (domain, vtable_slot);
1802 sorted = imt_sort_slot_entries (entries);
1804 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1808 MonoImtBuilderEntry *next = entries->next;
1813 for (i = 0; i < sorted->len; ++i)
1814 g_free (g_ptr_array_index (sorted, i));
1815 g_ptr_array_free (sorted, TRUE);
1818 #ifndef __native_client__
1819 /* We don't re-use any thunks as there is a lot of overhead */
1820 /* to deleting and re-using code in Native Client. */
1821 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1822 invalidate_generic_virtual_thunk (domain, old_thunk);
1826 mono_domain_unlock (domain);
1829 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1832 * mono_class_vtable:
1833 * @domain: the application domain
1834 * @class: the class to initialize
1836 * VTables are domain specific because we create domain specific code, and
1837 * they contain the domain specific static class data.
1838 * On failure, NULL is returned, and class->exception_type is set.
1841 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1843 return mono_class_vtable_full (domain, klass, FALSE);
1847 * mono_class_vtable_full:
1848 * @domain: the application domain
1849 * @class: the class to initialize
1850 * @raise_on_error if an exception should be raised on failure or not
1852 * VTables are domain specific because we create domain specific code, and
1853 * they contain the domain specific static class data.
1856 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1858 MONO_REQ_GC_UNSAFE_MODE;
1860 MonoClassRuntimeInfo *runtime_info;
1864 if (klass->exception_type) {
1866 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1870 /* this check can be inlined in jitted code, too */
1871 runtime_info = klass->runtime_info;
1872 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1873 return runtime_info->domain_vtables [domain->domain_id];
1874 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1878 * mono_class_try_get_vtable:
1879 * @domain: the application domain
1880 * @class: the class to initialize
1882 * This function tries to get the associated vtable from @class if
1883 * it was already created.
1886 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1888 MONO_REQ_GC_NEUTRAL_MODE;
1890 MonoClassRuntimeInfo *runtime_info;
1894 runtime_info = klass->runtime_info;
1895 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1896 return runtime_info->domain_vtables [domain->domain_id];
1901 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1903 MONO_REQ_GC_NEUTRAL_MODE;
1905 size_t alloc_offset;
1908 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1909 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1910 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1912 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1913 g_assert ((imt_table_bytes & 7) == 4);
1920 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1924 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1926 MONO_REQ_GC_UNSAFE_MODE;
1929 MonoClassRuntimeInfo *runtime_info, *old_info;
1930 MonoClassField *field;
1932 int i, vtable_slots;
1933 size_t imt_table_bytes;
1935 guint32 vtable_size, class_size;
1937 gpointer *interface_offsets;
1939 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1940 mono_domain_lock (domain);
1941 runtime_info = klass->runtime_info;
1942 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1943 mono_domain_unlock (domain);
1944 mono_loader_unlock ();
1945 return runtime_info->domain_vtables [domain->domain_id];
1947 if (!klass->inited || klass->exception_type) {
1948 if (!mono_class_init (klass) || klass->exception_type) {
1949 mono_domain_unlock (domain);
1950 mono_loader_unlock ();
1952 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1957 /* Array types require that their element type be valid*/
1958 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1959 MonoClass *element_class = klass->element_class;
1960 if (!element_class->inited)
1961 mono_class_init (element_class);
1963 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1964 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1965 mono_class_setup_vtable (element_class);
1967 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1968 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1969 if (klass->exception_type == MONO_EXCEPTION_NONE)
1970 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1971 mono_domain_unlock (domain);
1972 mono_loader_unlock ();
1974 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1980 * For some classes, mono_class_init () already computed klass->vtable_size, and
1981 * that is all that is needed because of the vtable trampolines.
1983 if (!klass->vtable_size)
1984 mono_class_setup_vtable (klass);
1986 if (klass->generic_class && !klass->vtable)
1987 mono_class_check_vtable_constraints (klass, NULL);
1989 /* Initialize klass->has_finalize */
1990 mono_class_has_finalizer (klass);
1992 if (klass->exception_type) {
1993 mono_domain_unlock (domain);
1994 mono_loader_unlock ();
1996 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2000 vtable_slots = klass->vtable_size;
2001 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2002 class_size = mono_class_data_size (klass);
2006 if (klass->interface_offsets_count) {
2007 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2008 mono_stats.imt_number_of_tables++;
2009 mono_stats.imt_tables_size += imt_table_bytes;
2011 imt_table_bytes = 0;
2014 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2016 mono_stats.used_class_count++;
2017 mono_stats.class_vtable_size += vtable_size;
2019 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2020 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2021 g_assert (!((gsize)vt & 7));
2024 vt->rank = klass->rank;
2025 vt->domain = domain;
2027 mono_class_compute_gc_descriptor (klass);
2029 * We can't use typed allocation in the non-root domains, since the
2030 * collector needs the GC descriptor stored in the vtable even after
2031 * the mempool containing the vtable is destroyed when the domain is
2032 * unloaded. An alternative might be to allocate vtables in the GC
2033 * heap, but this does not seem to work (it leads to crashes inside
2034 * libgc). If that approach is tried, two gc descriptors need to be
2035 * allocated for each class: one for the root domain, and one for all
2036 * other domains. The second descriptor should contain a bit for the
2037 * vtable field in MonoObject, since we can no longer assume the
2038 * vtable is reachable by other roots after the appdomain is unloaded.
2040 #ifdef HAVE_BOEHM_GC
2041 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2042 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2045 vt->gc_descr = klass->gc_descr;
2047 gc_bits = mono_gc_get_vtable_bits (klass);
2048 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2050 vt->gc_bits = gc_bits;
2053 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2054 if (klass->has_static_refs) {
2055 MonoGCDescriptor statics_gc_descr;
2057 gsize default_bitmap [4] = {0};
2060 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2061 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2062 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2063 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2064 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2065 if (bitmap != default_bitmap)
2068 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2070 vt->has_static_fields = TRUE;
2071 mono_stats.class_static_data_size += class_size;
2075 while ((field = mono_class_get_fields (klass, &iter))) {
2076 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2078 if (mono_field_is_deleted (field))
2080 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2081 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2082 if (special_static != SPECIAL_STATIC_NONE) {
2083 guint32 size, offset;
2085 gsize default_bitmap [4] = {0};
2090 if (mono_type_is_reference (field->type)) {
2091 default_bitmap [0] = 1;
2093 bitmap = default_bitmap;
2094 } else if (mono_type_is_struct (field->type)) {
2095 fclass = mono_class_from_mono_type (field->type);
2096 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2097 numbits = max_set + 1;
2099 default_bitmap [0] = 0;
2101 bitmap = default_bitmap;
2103 size = mono_type_size (field->type, &align);
2104 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2105 if (!domain->special_static_fields)
2106 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2107 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2108 if (bitmap != default_bitmap)
2111 * This marks the field as special static to speed up the
2112 * checks in mono_field_static_get/set_value ().
2118 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2119 MonoClass *fklass = mono_class_from_mono_type (field->type);
2120 const char *data = mono_field_get_data (field);
2122 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2123 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2124 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2127 if (fklass->valuetype) {
2128 memcpy (t, data, mono_class_value_size (fklass, NULL));
2130 /* it's a pointer type: add check */
2131 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2138 vt->max_interface_id = klass->max_interface_id;
2139 vt->interface_bitmap = klass->interface_bitmap;
2141 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2142 // class->name, klass->interface_offsets_count);
2144 /* Initialize vtable */
2145 if (callbacks.get_vtable_trampoline) {
2146 // This also covers the AOT case
2147 for (i = 0; i < klass->vtable_size; ++i) {
2148 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2151 mono_class_setup_vtable (klass);
2153 for (i = 0; i < klass->vtable_size; ++i) {
2156 if ((cm = klass->vtable [i]))
2157 vt->vtable [i] = arch_create_jit_trampoline (cm);
2161 if (imt_table_bytes) {
2162 /* Now that the vtable is full, we can actually fill up the IMT */
2163 for (i = 0; i < MONO_IMT_SIZE; ++i)
2164 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2168 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2169 * re-acquire them and check if another thread has created the vtable in the meantime.
2171 /* Special case System.MonoType to avoid infinite recursion */
2172 if (klass != mono_defaults.monotype_class) {
2173 /*FIXME check for OOM*/
2174 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2175 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2176 /* This is unregistered in
2177 unregister_vtable_reflection_type() in
2179 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2182 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2184 /* class_vtable_array keeps an array of created vtables
2186 g_ptr_array_add (domain->class_vtable_array, vt);
2187 /* klass->runtime_info is protected by the loader lock, both when
2188 * it it enlarged and when it is stored info.
2192 * Store the vtable in klass->runtime_info.
2193 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2195 mono_memory_barrier ();
2197 old_info = klass->runtime_info;
2198 if (old_info && old_info->max_domain >= domain->domain_id) {
2199 /* someone already created a large enough runtime info */
2200 old_info->domain_vtables [domain->domain_id] = vt;
2202 int new_size = domain->domain_id;
2204 new_size = MAX (new_size, old_info->max_domain);
2206 /* make the new size a power of two */
2208 while (new_size > i)
2211 /* this is a bounded memory retention issue: may want to
2212 * handle it differently when we'll have a rcu-like system.
2214 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2215 runtime_info->max_domain = new_size - 1;
2216 /* copy the stuff from the older info */
2218 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2220 runtime_info->domain_vtables [domain->domain_id] = vt;
2222 mono_memory_barrier ();
2223 klass->runtime_info = runtime_info;
2226 if (klass == mono_defaults.monotype_class) {
2227 /*FIXME check for OOM*/
2228 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2229 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2230 /* This is unregistered in
2231 unregister_vtable_reflection_type() in
2233 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2236 mono_domain_unlock (domain);
2237 mono_loader_unlock ();
2239 /* make sure the parent is initialized */
2240 /*FIXME shouldn't this fail the current type?*/
2242 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2247 #ifndef DISABLE_REMOTING
2249 * mono_class_proxy_vtable:
2250 * @domain: the application domain
2251 * @remove_class: the remote class
2253 * Creates a vtable for transparent proxies. It is basically
2254 * a copy of the real vtable of the class wrapped in @remote_class,
2255 * but all function pointers invoke the remoting functions, and
2256 * vtable->klass points to the transparent proxy class, and not to @class.
2259 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2261 MONO_REQ_GC_UNSAFE_MODE;
2264 MonoVTable *vt, *pvt;
2265 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2267 GSList *extra_interfaces = NULL;
2268 MonoClass *klass = remote_class->proxy_class;
2269 gpointer *interface_offsets;
2272 size_t imt_table_bytes;
2274 #ifdef COMPRESSED_INTERFACE_BITMAP
2278 vt = mono_class_vtable (domain, klass);
2279 g_assert (vt); /*FIXME property handle failure*/
2280 max_interface_id = vt->max_interface_id;
2282 /* Calculate vtable space for extra interfaces */
2283 for (j = 0; j < remote_class->interface_count; j++) {
2284 MonoClass* iclass = remote_class->interfaces[j];
2288 /*FIXME test for interfaces with variant generic arguments*/
2289 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2290 continue; /* interface implemented by the class */
2291 if (g_slist_find (extra_interfaces, iclass))
2294 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2296 method_count = mono_class_num_methods (iclass);
2298 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2299 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2301 for (i = 0; i < ifaces->len; ++i) {
2302 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2303 /*FIXME test for interfaces with variant generic arguments*/
2304 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2305 continue; /* interface implemented by the class */
2306 if (g_slist_find (extra_interfaces, ic))
2308 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2309 method_count += mono_class_num_methods (ic);
2311 g_ptr_array_free (ifaces, TRUE);
2314 extra_interface_vtsize += method_count * sizeof (gpointer);
2315 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2318 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2319 mono_stats.imt_number_of_tables++;
2320 mono_stats.imt_tables_size += imt_table_bytes;
2322 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2324 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2326 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2327 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2328 g_assert (!((gsize)pvt & 7));
2330 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2332 pvt->klass = mono_defaults.transparent_proxy_class;
2333 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2334 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2336 /* initialize vtable */
2337 mono_class_setup_vtable (klass);
2338 for (i = 0; i < klass->vtable_size; ++i) {
2341 if ((cm = klass->vtable [i]))
2342 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2344 pvt->vtable [i] = NULL;
2347 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2348 /* create trampolines for abstract methods */
2349 for (k = klass; k; k = k->parent) {
2351 gpointer iter = NULL;
2352 while ((m = mono_class_get_methods (k, &iter)))
2353 if (!pvt->vtable [m->slot])
2354 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2358 pvt->max_interface_id = max_interface_id;
2359 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2360 #ifdef COMPRESSED_INTERFACE_BITMAP
2361 bitmap = (uint8_t *)g_malloc0 (bsize);
2363 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2366 for (i = 0; i < klass->interface_offsets_count; ++i) {
2367 int interface_id = klass->interfaces_packed [i]->interface_id;
2368 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2371 if (extra_interfaces) {
2372 int slot = klass->vtable_size;
2378 /* Create trampolines for the methods of the interfaces */
2379 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2380 interf = (MonoClass *)list_item->data;
2382 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2386 while ((cm = mono_class_get_methods (interf, &iter)))
2387 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2389 slot += mono_class_num_methods (interf);
2393 /* Now that the vtable is full, we can actually fill up the IMT */
2394 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2395 if (extra_interfaces) {
2396 g_slist_free (extra_interfaces);
2399 #ifdef COMPRESSED_INTERFACE_BITMAP
2400 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2401 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2402 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2405 pvt->interface_bitmap = bitmap;
2410 #endif /* DISABLE_REMOTING */
2413 * mono_class_field_is_special_static:
2415 * Returns whether @field is a thread/context static field.
2418 mono_class_field_is_special_static (MonoClassField *field)
2420 MONO_REQ_GC_NEUTRAL_MODE
2422 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2424 if (mono_field_is_deleted (field))
2426 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2427 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2434 * mono_class_field_get_special_static_type:
2435 * @field: The MonoClassField describing the field.
2437 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2438 * SPECIAL_STATIC_NONE otherwise.
2441 mono_class_field_get_special_static_type (MonoClassField *field)
2443 MONO_REQ_GC_NEUTRAL_MODE
2445 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2446 return SPECIAL_STATIC_NONE;
2447 if (mono_field_is_deleted (field))
2448 return SPECIAL_STATIC_NONE;
2449 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2450 return field_is_special_static (field->parent, field);
2451 return SPECIAL_STATIC_NONE;
2455 * mono_class_has_special_static_fields:
2457 * Returns whenever @klass has any thread/context static fields.
2460 mono_class_has_special_static_fields (MonoClass *klass)
2462 MONO_REQ_GC_NEUTRAL_MODE
2464 MonoClassField *field;
2468 while ((field = mono_class_get_fields (klass, &iter))) {
2469 g_assert (field->parent == klass);
2470 if (mono_class_field_is_special_static (field))
2477 #ifndef DISABLE_REMOTING
2479 * create_remote_class_key:
2480 * Creates an array of pointers that can be used as a hash key for a remote class.
2481 * The first element of the array is the number of pointers.
2484 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2486 MONO_REQ_GC_NEUTRAL_MODE;
2491 if (remote_class == NULL) {
2492 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2493 key = (void **)g_malloc (sizeof(gpointer) * 3);
2494 key [0] = GINT_TO_POINTER (2);
2495 key [1] = mono_defaults.marshalbyrefobject_class;
2496 key [2] = extra_class;
2498 key = (void **)g_malloc (sizeof(gpointer) * 2);
2499 key [0] = GINT_TO_POINTER (1);
2500 key [1] = extra_class;
2503 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2504 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2505 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2506 key [1] = remote_class->proxy_class;
2508 // Keep the list of interfaces sorted
2509 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2510 if (extra_class && remote_class->interfaces [i] > extra_class) {
2511 key [j++] = extra_class;
2514 key [j] = remote_class->interfaces [i];
2517 key [j] = extra_class;
2519 // Replace the old class. The interface list is the same
2520 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2521 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2522 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2523 for (i = 0; i < remote_class->interface_count; i++)
2524 key [2 + i] = remote_class->interfaces [i];
2532 * copy_remote_class_key:
2534 * Make a copy of KEY in the domain and return the copy.
2537 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2539 MONO_REQ_GC_NEUTRAL_MODE
2541 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2542 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2544 memcpy (mp_key, key, key_size);
2550 * mono_remote_class:
2551 * @domain: the application domain
2552 * @class_name: name of the remote class
2554 * Creates and initializes a MonoRemoteClass object for a remote type.
2556 * Can raise an exception on failure.
2559 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2561 MONO_REQ_GC_UNSAFE_MODE;
2564 MonoRemoteClass *rc;
2565 gpointer* key, *mp_key;
2568 key = create_remote_class_key (NULL, proxy_class);
2570 mono_domain_lock (domain);
2571 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2575 mono_domain_unlock (domain);
2579 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2580 if (!mono_error_ok (&error)) {
2582 mono_domain_unlock (domain);
2583 mono_error_raise_exception (&error);
2586 mp_key = copy_remote_class_key (domain, key);
2590 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2591 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2592 rc->interface_count = 1;
2593 rc->interfaces [0] = proxy_class;
2594 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2596 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2597 rc->interface_count = 0;
2598 rc->proxy_class = proxy_class;
2601 rc->default_vtable = NULL;
2602 rc->xdomain_vtable = NULL;
2603 rc->proxy_class_name = name;
2604 #ifndef DISABLE_PERFCOUNTERS
2605 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2608 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2610 mono_domain_unlock (domain);
2615 * clone_remote_class:
2616 * Creates a copy of the remote_class, adding the provided class or interface
2618 static MonoRemoteClass*
2619 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2621 MONO_REQ_GC_NEUTRAL_MODE;
2623 MonoRemoteClass *rc;
2624 gpointer* key, *mp_key;
2626 key = create_remote_class_key (remote_class, extra_class);
2627 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2633 mp_key = copy_remote_class_key (domain, key);
2637 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2639 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2640 rc->proxy_class = remote_class->proxy_class;
2641 rc->interface_count = remote_class->interface_count + 1;
2643 // Keep the list of interfaces sorted, since the hash key of
2644 // the remote class depends on this
2645 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2646 if (remote_class->interfaces [i] > extra_class && i == j)
2647 rc->interfaces [j++] = extra_class;
2648 rc->interfaces [j] = remote_class->interfaces [i];
2651 rc->interfaces [j] = extra_class;
2653 // Replace the old class. The interface array is the same
2654 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2655 rc->proxy_class = extra_class;
2656 rc->interface_count = remote_class->interface_count;
2657 if (rc->interface_count > 0)
2658 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2661 rc->default_vtable = NULL;
2662 rc->xdomain_vtable = NULL;
2663 rc->proxy_class_name = remote_class->proxy_class_name;
2665 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2671 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2673 MONO_REQ_GC_UNSAFE_MODE;
2675 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2676 mono_domain_lock (domain);
2677 if (rp->target_domain_id != -1) {
2678 if (remote_class->xdomain_vtable == NULL)
2679 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2680 mono_domain_unlock (domain);
2681 mono_loader_unlock ();
2682 return remote_class->xdomain_vtable;
2684 if (remote_class->default_vtable == NULL) {
2687 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2688 klass = mono_class_from_mono_type (type);
2690 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)))
2691 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2694 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2697 mono_domain_unlock (domain);
2698 mono_loader_unlock ();
2699 return remote_class->default_vtable;
2703 * mono_upgrade_remote_class:
2704 * @domain: the application domain
2705 * @tproxy: the proxy whose remote class has to be upgraded.
2706 * @klass: class to which the remote class can be casted.
2708 * Updates the vtable of the remote class by adding the necessary method slots
2709 * and interface offsets so it can be safely casted to klass. klass can be a
2710 * class or an interface.
2713 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2715 MONO_REQ_GC_UNSAFE_MODE;
2717 MonoTransparentProxy *tproxy;
2718 MonoRemoteClass *remote_class;
2719 gboolean redo_vtable;
2721 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2722 mono_domain_lock (domain);
2724 tproxy = (MonoTransparentProxy*) proxy_object;
2725 remote_class = tproxy->remote_class;
2727 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2730 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2731 if (remote_class->interfaces [i] == klass)
2732 redo_vtable = FALSE;
2735 redo_vtable = (remote_class->proxy_class != klass);
2739 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2740 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2743 mono_domain_unlock (domain);
2744 mono_loader_unlock ();
2746 #endif /* DISABLE_REMOTING */
2750 * mono_object_get_virtual_method:
2751 * @obj: object to operate on.
2754 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2755 * the instance of a callvirt of method.
2758 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2760 MONO_REQ_GC_UNSAFE_MODE;
2763 MonoMethod **vtable;
2764 gboolean is_proxy = FALSE;
2765 MonoMethod *res = NULL;
2767 klass = mono_object_class (obj);
2768 #ifndef DISABLE_REMOTING
2769 if (klass == mono_defaults.transparent_proxy_class) {
2770 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2775 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2778 mono_class_setup_vtable (klass);
2779 vtable = klass->vtable;
2781 if (method->slot == -1) {
2782 /* method->slot might not be set for instances of generic methods */
2783 if (method->is_inflated) {
2784 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2785 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2788 g_assert_not_reached ();
2792 /* check method->slot is a valid index: perform isinstance? */
2793 if (method->slot != -1) {
2794 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2796 gboolean variance_used = FALSE;
2797 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2798 g_assert (iface_offset > 0);
2799 res = vtable [iface_offset + method->slot];
2802 res = vtable [method->slot];
2806 #ifndef DISABLE_REMOTING
2808 /* It may be an interface, abstract class method or generic method */
2809 if (!res || mono_method_signature (res)->generic_param_count)
2812 /* generic methods demand invoke_with_check */
2813 if (mono_method_signature (res)->generic_param_count)
2814 res = mono_marshal_get_remoting_invoke_with_check (res);
2817 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2818 res = mono_cominterop_get_invoke (res);
2821 res = mono_marshal_get_remoting_invoke (res);
2826 if (method->is_inflated) {
2828 /* Have to inflate the result */
2829 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2830 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2840 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2842 g_error ("runtime invoke called on uninitialized runtime");
2846 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2849 * mono_runtime_invoke:
2850 * @method: method to invoke
2851 * @obJ: object instance
2852 * @params: arguments to the method
2853 * @exc: exception information.
2855 * Invokes the method represented by @method on the object @obj.
2857 * obj is the 'this' pointer, it should be NULL for static
2858 * methods, a MonoObject* for object instances and a pointer to
2859 * the value type for value types.
2861 * The params array contains the arguments to the method with the
2862 * same convention: MonoObject* pointers for object instances and
2863 * pointers to the value type otherwise.
2865 * From unmanaged code you'll usually use the
2866 * mono_runtime_invoke() variant.
2868 * Note that this function doesn't handle virtual methods for
2869 * you, it will exec the exact method you pass: we still need to
2870 * expose a function to lookup the derived class implementation
2871 * of a virtual method (there are examples of this in the code,
2874 * You can pass NULL as the exc argument if you don't want to
2875 * catch exceptions, otherwise, *exc will be set to the exception
2876 * thrown, if any. if an exception is thrown, you can't use the
2877 * MonoObject* result from the function.
2879 * If the method returns a value type, it is boxed in an object
2883 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2885 MONO_REQ_GC_UNSAFE_MODE;
2889 if (mono_runtime_get_no_exec ())
2890 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2892 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2893 mono_profiler_method_start_invoke (method);
2895 result = default_mono_runtime_invoke (method, obj, params, exc);
2897 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2898 mono_profiler_method_end_invoke (method);
2904 * mono_method_get_unmanaged_thunk:
2905 * @method: method to generate a thunk for.
2907 * Returns an unmanaged->managed thunk that can be used to call
2908 * a managed method directly from C.
2910 * The thunk's C signature closely matches the managed signature:
2912 * C#: public bool Equals (object obj);
2913 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2914 * MonoObject*, MonoException**);
2916 * The 1st ("this") parameter must not be used with static methods:
2918 * C#: public static bool ReferenceEquals (object a, object b);
2919 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2922 * The last argument must be a non-null pointer of a MonoException* pointer.
2923 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2924 * exception has been thrown in managed code. Otherwise it will point
2925 * to the MonoException* caught by the thunk. In this case, the result of
2926 * the thunk is undefined:
2928 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2929 * MonoException *ex = NULL;
2930 * Equals func = mono_method_get_unmanaged_thunk (method);
2931 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2933 * // handle exception
2936 * The calling convention of the thunk matches the platform's default
2937 * convention. This means that under Windows, C declarations must
2938 * contain the __stdcall attribute:
2940 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2941 * MonoObject*, MonoException**);
2945 * Value type arguments and return values are treated as they were objects:
2947 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2948 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2950 * Arguments must be properly boxed upon trunk's invocation, while return
2951 * values must be unboxed.
2954 mono_method_get_unmanaged_thunk (MonoMethod *method)
2956 MONO_REQ_GC_NEUTRAL_MODE;
2957 MONO_REQ_API_ENTRYPOINT;
2961 MONO_PREPARE_RESET_BLOCKING;
2962 method = mono_marshal_get_thunk_invoke_wrapper (method);
2963 res = mono_compile_method (method);
2964 MONO_FINISH_RESET_BLOCKING;
2970 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2972 MONO_REQ_GC_UNSAFE_MODE;
2976 /* object fields cannot be byref, so we don't need a
2978 gpointer *p = (gpointer*)dest;
2985 case MONO_TYPE_BOOLEAN:
2987 case MONO_TYPE_U1: {
2988 guint8 *p = (guint8*)dest;
2989 *p = value ? *(guint8*)value : 0;
2994 case MONO_TYPE_CHAR: {
2995 guint16 *p = (guint16*)dest;
2996 *p = value ? *(guint16*)value : 0;
2999 #if SIZEOF_VOID_P == 4
3004 case MONO_TYPE_U4: {
3005 gint32 *p = (gint32*)dest;
3006 *p = value ? *(gint32*)value : 0;
3009 #if SIZEOF_VOID_P == 8
3014 case MONO_TYPE_U8: {
3015 gint64 *p = (gint64*)dest;
3016 *p = value ? *(gint64*)value : 0;
3019 case MONO_TYPE_R4: {
3020 float *p = (float*)dest;
3021 *p = value ? *(float*)value : 0;
3024 case MONO_TYPE_R8: {
3025 double *p = (double*)dest;
3026 *p = value ? *(double*)value : 0;
3029 case MONO_TYPE_STRING:
3030 case MONO_TYPE_SZARRAY:
3031 case MONO_TYPE_CLASS:
3032 case MONO_TYPE_OBJECT:
3033 case MONO_TYPE_ARRAY:
3034 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3036 case MONO_TYPE_FNPTR:
3037 case MONO_TYPE_PTR: {
3038 gpointer *p = (gpointer*)dest;
3039 *p = deref_pointer? *(gpointer*)value: value;
3042 case MONO_TYPE_VALUETYPE:
3043 /* note that 't' and 'type->type' can be different */
3044 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3045 t = mono_class_enum_basetype (type->data.klass)->type;
3048 MonoClass *klass = mono_class_from_mono_type (type);
3049 int size = mono_class_value_size (klass, NULL);
3051 mono_gc_bzero_atomic (dest, size);
3053 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3056 case MONO_TYPE_GENERICINST:
3057 t = type->data.generic_class->container_class->byval_arg.type;
3060 g_error ("got type %x", type->type);
3065 * mono_field_set_value:
3066 * @obj: Instance object
3067 * @field: MonoClassField describing the field to set
3068 * @value: The value to be set
3070 * Sets the value of the field described by @field in the object instance @obj
3071 * to the value passed in @value. This method should only be used for instance
3072 * fields. For static fields, use mono_field_static_set_value.
3074 * The value must be on the native format of the field type.
3077 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3079 MONO_REQ_GC_UNSAFE_MODE;
3083 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3085 dest = (char*)obj + field->offset;
3086 mono_copy_value (field->type, dest, value, FALSE);
3090 * mono_field_static_set_value:
3091 * @field: MonoClassField describing the field to set
3092 * @value: The value to be set
3094 * Sets the value of the static field described by @field
3095 * to the value passed in @value.
3097 * The value must be on the native format of the field type.
3100 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3102 MONO_REQ_GC_UNSAFE_MODE;
3106 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3107 /* you cant set a constant! */
3108 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3110 if (field->offset == -1) {
3111 /* Special static */
3114 mono_domain_lock (vt->domain);
3115 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3116 mono_domain_unlock (vt->domain);
3117 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3119 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3121 mono_copy_value (field->type, dest, value, FALSE);
3125 * mono_vtable_get_static_field_data:
3127 * Internal use function: return a pointer to the memory holding the static fields
3128 * for a class or NULL if there are no static fields.
3129 * This is exported only for use by the debugger.
3132 mono_vtable_get_static_field_data (MonoVTable *vt)
3134 MONO_REQ_GC_NEUTRAL_MODE
3136 if (!vt->has_static_fields)
3138 return vt->vtable [vt->klass->vtable_size];
3142 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3144 MONO_REQ_GC_UNSAFE_MODE;
3148 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3149 if (field->offset == -1) {
3150 /* Special static */
3153 mono_domain_lock (vt->domain);
3154 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3155 mono_domain_unlock (vt->domain);
3156 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3158 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3161 src = (guint8*)obj + field->offset;
3168 * mono_field_get_value:
3169 * @obj: Object instance
3170 * @field: MonoClassField describing the field to fetch information from
3171 * @value: pointer to the location where the value will be stored
3173 * Use this routine to get the value of the field @field in the object
3176 * The pointer provided by value must be of the field type, for reference
3177 * types this is a MonoObject*, for value types its the actual pointer to
3182 * mono_field_get_value (obj, int_field, &i);
3185 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3187 MONO_REQ_GC_UNSAFE_MODE;
3193 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3195 src = (char*)obj + field->offset;
3196 mono_copy_value (field->type, value, src, TRUE);
3200 * mono_field_get_value_object:
3201 * @domain: domain where the object will be created (if boxing)
3202 * @field: MonoClassField describing the field to fetch information from
3203 * @obj: The object instance for the field.
3205 * Returns: a new MonoObject with the value from the given field. If the
3206 * field represents a value type, the value is boxed.
3210 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3212 MONO_REQ_GC_UNSAFE_MODE;
3216 MonoVTable *vtable = NULL;
3218 gboolean is_static = FALSE;
3219 gboolean is_ref = FALSE;
3220 gboolean is_literal = FALSE;
3221 gboolean is_ptr = FALSE;
3223 MonoType *type = mono_field_get_type_checked (field, &error);
3225 if (!mono_error_ok (&error))
3226 mono_error_raise_exception (&error);
3228 switch (type->type) {
3229 case MONO_TYPE_STRING:
3230 case MONO_TYPE_OBJECT:
3231 case MONO_TYPE_CLASS:
3232 case MONO_TYPE_ARRAY:
3233 case MONO_TYPE_SZARRAY:
3238 case MONO_TYPE_BOOLEAN:
3241 case MONO_TYPE_CHAR:
3250 case MONO_TYPE_VALUETYPE:
3251 is_ref = type->byref;
3253 case MONO_TYPE_GENERICINST:
3254 is_ref = !mono_type_generic_inst_is_valuetype (type);
3260 g_error ("type 0x%x not handled in "
3261 "mono_field_get_value_object", type->type);
3265 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3268 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3272 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3273 if (!vtable->initialized)
3274 mono_runtime_class_init (vtable);
3282 get_default_field_value (domain, field, &o);
3283 } else if (is_static) {
3284 mono_field_static_get_value (vtable, field, &o);
3286 mono_field_get_value (obj, field, &o);
3292 static MonoMethod *m;
3298 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3299 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3305 get_default_field_value (domain, field, v);
3306 } else if (is_static) {
3307 mono_field_static_get_value (vtable, field, v);
3309 mono_field_get_value (obj, field, v);
3312 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3313 args [0] = ptr ? *ptr : NULL;
3314 args [1] = mono_type_get_object (mono_domain_get (), type);
3316 return mono_runtime_invoke (m, NULL, args, NULL);
3319 /* boxed value type */
3320 klass = mono_class_from_mono_type (type);
3322 if (mono_class_is_nullable (klass))
3323 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3325 o = mono_object_new (domain, klass);
3326 v = ((gchar *) o) + sizeof (MonoObject);
3329 get_default_field_value (domain, field, v);
3330 } else if (is_static) {
3331 mono_field_static_get_value (vtable, field, v);
3333 mono_field_get_value (obj, field, v);
3340 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3342 MONO_REQ_GC_UNSAFE_MODE;
3345 const char *p = blob;
3346 mono_metadata_decode_blob_size (p, &p);
3349 case MONO_TYPE_BOOLEAN:
3352 *(guint8 *) value = *p;
3354 case MONO_TYPE_CHAR:
3357 *(guint16*) value = read16 (p);
3361 *(guint32*) value = read32 (p);
3365 *(guint64*) value = read64 (p);
3368 readr4 (p, (float*) value);
3371 readr8 (p, (double*) value);
3373 case MONO_TYPE_STRING:
3374 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3376 case MONO_TYPE_CLASS:
3377 *(gpointer*) value = NULL;
3381 g_warning ("type 0x%02x should not be in constant table", type);
3387 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3389 MONO_REQ_GC_NEUTRAL_MODE;
3391 MonoTypeEnum def_type;
3394 data = mono_class_get_field_default_value (field, &def_type);
3395 mono_get_constant_value_from_blob (domain, def_type, data, value);
3399 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3401 MONO_REQ_GC_UNSAFE_MODE;
3405 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3407 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3408 get_default_field_value (vt->domain, field, value);
3412 if (field->offset == -1) {
3413 /* Special static */
3414 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3415 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3417 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3419 mono_copy_value (field->type, value, src, TRUE);
3423 * mono_field_static_get_value:
3424 * @vt: vtable to the object
3425 * @field: MonoClassField describing the field to fetch information from
3426 * @value: where the value is returned
3428 * Use this routine to get the value of the static field @field value.
3430 * The pointer provided by value must be of the field type, for reference
3431 * types this is a MonoObject*, for value types its the actual pointer to
3436 * mono_field_static_get_value (vt, int_field, &i);
3439 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3441 MONO_REQ_GC_NEUTRAL_MODE;
3443 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3447 * mono_property_set_value:
3448 * @prop: MonoProperty to set
3449 * @obj: instance object on which to act
3450 * @params: parameters to pass to the propery
3451 * @exc: optional exception
3453 * Invokes the property's set method with the given arguments on the
3454 * object instance obj (or NULL for static properties).
3456 * You can pass NULL as the exc argument if you don't want to
3457 * catch exceptions, otherwise, *exc will be set to the exception
3458 * thrown, if any. if an exception is thrown, you can't use the
3459 * MonoObject* result from the function.
3462 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3464 MONO_REQ_GC_UNSAFE_MODE;
3466 default_mono_runtime_invoke (prop->set, obj, params, exc);
3470 * mono_property_get_value:
3471 * @prop: MonoProperty to fetch
3472 * @obj: instance object on which to act
3473 * @params: parameters to pass to the propery
3474 * @exc: optional exception
3476 * Invokes the property's get method with the given arguments on the
3477 * object instance obj (or NULL for static properties).
3479 * You can pass NULL as the exc argument if you don't want to
3480 * catch exceptions, otherwise, *exc will be set to the exception
3481 * thrown, if any. if an exception is thrown, you can't use the
3482 * MonoObject* result from the function.
3484 * Returns: the value from invoking the get method on the property.
3487 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3489 MONO_REQ_GC_UNSAFE_MODE;
3491 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3495 * mono_nullable_init:
3496 * @buf: The nullable structure to initialize.
3497 * @value: the value to initialize from
3498 * @klass: the type for the object
3500 * Initialize the nullable structure pointed to by @buf from @value which
3501 * should be a boxed value type. The size of @buf should be able to hold
3502 * as much data as the @klass->instance_size (which is the number of bytes
3503 * that will be copies).
3505 * Since Nullables have variable structure, we can not define a C
3506 * structure for them.
3509 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3511 MONO_REQ_GC_UNSAFE_MODE;
3513 MonoClass *param_class = klass->cast_class;
3515 mono_class_setup_fields_locking (klass);
3516 g_assert (klass->fields_inited);
3518 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3519 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3521 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3523 if (param_class->has_references)
3524 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3526 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3528 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3533 * mono_nullable_box:
3534 * @buf: The buffer representing the data to be boxed
3535 * @klass: the type to box it as.
3537 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3541 mono_nullable_box (guint8 *buf, MonoClass *klass)
3543 MONO_REQ_GC_UNSAFE_MODE;
3545 MonoClass *param_class = klass->cast_class;
3547 mono_class_setup_fields_locking (klass);
3548 g_assert (klass->fields_inited);
3550 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3551 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3553 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3554 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3555 if (param_class->has_references)
3556 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3558 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3566 * mono_get_delegate_invoke:
3567 * @klass: The delegate class
3569 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3572 mono_get_delegate_invoke (MonoClass *klass)
3574 MONO_REQ_GC_NEUTRAL_MODE;
3578 /* This is called at runtime, so avoid the slower search in metadata */
3579 mono_class_setup_methods (klass);
3580 if (klass->exception_type)
3582 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3587 * mono_get_delegate_begin_invoke:
3588 * @klass: The delegate class
3590 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3593 mono_get_delegate_begin_invoke (MonoClass *klass)
3595 MONO_REQ_GC_NEUTRAL_MODE;
3599 /* This is called at runtime, so avoid the slower search in metadata */
3600 mono_class_setup_methods (klass);
3601 if (klass->exception_type)
3603 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3608 * mono_get_delegate_end_invoke:
3609 * @klass: The delegate class
3611 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3614 mono_get_delegate_end_invoke (MonoClass *klass)
3616 MONO_REQ_GC_NEUTRAL_MODE;
3620 /* This is called at runtime, so avoid the slower search in metadata */
3621 mono_class_setup_methods (klass);
3622 if (klass->exception_type)
3624 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3629 * mono_runtime_delegate_invoke:
3630 * @delegate: pointer to a delegate object.
3631 * @params: parameters for the delegate.
3632 * @exc: Pointer to the exception result.
3634 * Invokes the delegate method @delegate with the parameters provided.
3636 * You can pass NULL as the exc argument if you don't want to
3637 * catch exceptions, otherwise, *exc will be set to the exception
3638 * thrown, if any. if an exception is thrown, you can't use the
3639 * MonoObject* result from the function.
3642 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3644 MONO_REQ_GC_UNSAFE_MODE;
3647 MonoClass *klass = delegate->vtable->klass;
3649 im = mono_get_delegate_invoke (klass);
3651 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3653 return mono_runtime_invoke (im, delegate, params, exc);
3656 static char **main_args = NULL;
3657 static int num_main_args = 0;
3660 * mono_runtime_get_main_args:
3662 * Returns: a MonoArray with the arguments passed to the main program
3665 mono_runtime_get_main_args (void)
3667 MONO_REQ_GC_UNSAFE_MODE;
3671 MonoDomain *domain = mono_domain_get ();
3673 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3675 for (i = 0; i < num_main_args; ++i)
3676 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3682 free_main_args (void)
3684 MONO_REQ_GC_NEUTRAL_MODE;
3688 for (i = 0; i < num_main_args; ++i)
3689 g_free (main_args [i]);
3696 * mono_runtime_set_main_args:
3697 * @argc: number of arguments from the command line
3698 * @argv: array of strings from the command line
3700 * Set the command line arguments from an embedding application that doesn't otherwise call
3701 * mono_runtime_run_main ().
3704 mono_runtime_set_main_args (int argc, char* argv[])
3706 MONO_REQ_GC_NEUTRAL_MODE;
3711 main_args = g_new0 (char*, argc);
3712 num_main_args = argc;
3714 for (i = 0; i < argc; ++i) {
3717 utf8_arg = mono_utf8_from_external (argv[i]);
3718 if (utf8_arg == NULL) {
3719 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3720 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3724 main_args [i] = utf8_arg;
3731 * mono_runtime_run_main:
3732 * @method: the method to start the application with (usually Main)
3733 * @argc: number of arguments from the command line
3734 * @argv: array of strings from the command line
3735 * @exc: excetption results
3737 * Execute a standard Main() method (argc/argv contains the
3738 * executable name). This method also sets the command line argument value
3739 * needed by System.Environment.
3744 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3747 MONO_REQ_GC_UNSAFE_MODE;
3750 MonoArray *args = NULL;
3751 MonoDomain *domain = mono_domain_get ();
3752 gchar *utf8_fullpath;
3753 MonoMethodSignature *sig;
3755 g_assert (method != NULL);
3757 mono_thread_set_main (mono_thread_current ());
3759 main_args = g_new0 (char*, argc);
3760 num_main_args = argc;
3762 if (!g_path_is_absolute (argv [0])) {
3763 gchar *basename = g_path_get_basename (argv [0]);
3764 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3768 utf8_fullpath = mono_utf8_from_external (fullpath);
3769 if(utf8_fullpath == NULL) {
3770 /* Printing the arg text will cause glib to
3771 * whinge about "Invalid UTF-8", but at least
3772 * its relevant, and shows the problem text
3775 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3776 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3783 utf8_fullpath = mono_utf8_from_external (argv[0]);
3784 if(utf8_fullpath == NULL) {
3785 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3786 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3791 main_args [0] = utf8_fullpath;
3793 for (i = 1; i < argc; ++i) {
3796 utf8_arg=mono_utf8_from_external (argv[i]);
3797 if(utf8_arg==NULL) {
3798 /* Ditto the comment about Invalid UTF-8 here */
3799 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3800 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3804 main_args [i] = utf8_arg;
3809 sig = mono_method_signature (method);
3811 g_print ("Unable to load Main method.\n");
3815 if (sig->param_count) {
3816 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3817 for (i = 0; i < argc; ++i) {
3818 /* The encodings should all work, given that
3819 * we've checked all these args for the
3822 gchar *str = mono_utf8_from_external (argv [i]);
3823 MonoString *arg = mono_string_new (domain, str);
3824 mono_array_setref (args, i, arg);
3828 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3831 mono_assembly_set_main (method->klass->image->assembly);
3833 return mono_runtime_exec_main (method, args, exc);
3837 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3839 static MonoMethod *serialize_method;
3844 if (!serialize_method) {
3845 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3846 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3849 if (!serialize_method) {
3854 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3858 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3866 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3868 MONO_REQ_GC_UNSAFE_MODE;
3870 static MonoMethod *deserialize_method;
3875 if (!deserialize_method) {
3876 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3877 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3879 if (!deserialize_method) {
3886 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3893 #ifndef DISABLE_REMOTING
3895 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3897 MONO_REQ_GC_UNSAFE_MODE;
3899 static MonoMethod *get_proxy_method;
3901 MonoDomain *domain = mono_domain_get ();
3902 MonoRealProxy *real_proxy;
3903 MonoReflectionType *reflection_type;
3904 MonoTransparentProxy *transparent_proxy;
3906 if (!get_proxy_method)
3907 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3909 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3911 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3912 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3914 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3915 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3918 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3922 return (MonoObject*) transparent_proxy;
3924 #endif /* DISABLE_REMOTING */
3927 * mono_object_xdomain_representation
3929 * @target_domain: a domain
3930 * @exc: pointer to a MonoObject*
3932 * Creates a representation of obj in the domain target_domain. This
3933 * is either a copy of obj arrived through via serialization and
3934 * deserialization or a proxy, depending on whether the object is
3935 * serializable or marshal by ref. obj must not be in target_domain.
3937 * If the object cannot be represented in target_domain, NULL is
3938 * returned and *exc is set to an appropriate exception.
3941 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3943 MONO_REQ_GC_UNSAFE_MODE;
3945 MonoObject *deserialized = NULL;
3946 gboolean failure = FALSE;
3950 #ifndef DISABLE_REMOTING
3951 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3952 deserialized = make_transparent_proxy (obj, &failure, exc);
3957 MonoDomain *domain = mono_domain_get ();
3958 MonoObject *serialized;
3960 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3961 serialized = serialize_object (obj, &failure, exc);
3962 mono_domain_set_internal_with_options (target_domain, FALSE);
3964 deserialized = deserialize_object (serialized, &failure, exc);
3965 if (domain != target_domain)
3966 mono_domain_set_internal_with_options (domain, FALSE);
3969 return deserialized;
3972 /* Used in call_unhandled_exception_delegate */
3974 create_unhandled_exception_eventargs (MonoObject *exc)
3976 MONO_REQ_GC_UNSAFE_MODE;
3980 MonoMethod *method = NULL;
3981 MonoBoolean is_terminating = TRUE;
3984 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3987 mono_class_init (klass);
3989 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3990 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3994 args [1] = &is_terminating;
3996 obj = mono_object_new (mono_domain_get (), klass);
3997 mono_runtime_invoke (method, obj, args, NULL);
4002 /* Used in mono_unhandled_exception */
4004 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4005 MONO_REQ_GC_UNSAFE_MODE;
4007 MonoObject *e = NULL;
4009 MonoDomain *current_domain = mono_domain_get ();
4011 if (domain != current_domain)
4012 mono_domain_set_internal_with_options (domain, FALSE);
4014 g_assert (domain == mono_object_domain (domain->domain));
4016 if (mono_object_domain (exc) != domain) {
4017 MonoObject *serialization_exc;
4019 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4021 if (serialization_exc) {
4023 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4026 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4027 "System.Runtime.Serialization", "SerializationException",
4028 "Could not serialize unhandled exception.");
4032 g_assert (mono_object_domain (exc) == domain);
4034 pa [0] = domain->domain;
4035 pa [1] = create_unhandled_exception_eventargs (exc);
4036 mono_runtime_delegate_invoke (delegate, pa, &e);
4038 if (domain != current_domain)
4039 mono_domain_set_internal_with_options (current_domain, FALSE);
4043 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4044 if (!mono_error_ok (&error)) {
4045 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4046 mono_error_cleanup (&error);
4048 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4054 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4057 * mono_runtime_unhandled_exception_policy_set:
4058 * @policy: the new policy
4060 * This is a VM internal routine.
4062 * Sets the runtime policy for handling unhandled exceptions.
4065 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4066 runtime_unhandled_exception_policy = policy;
4070 * mono_runtime_unhandled_exception_policy_get:
4072 * This is a VM internal routine.
4074 * Gets the runtime policy for handling unhandled exceptions.
4076 MonoRuntimeUnhandledExceptionPolicy
4077 mono_runtime_unhandled_exception_policy_get (void) {
4078 return runtime_unhandled_exception_policy;
4082 * mono_unhandled_exception:
4083 * @exc: exception thrown
4085 * This is a VM internal routine.
4087 * We call this function when we detect an unhandled exception
4088 * in the default domain.
4090 * It invokes the * UnhandledException event in AppDomain or prints
4091 * a warning to the console
4094 mono_unhandled_exception (MonoObject *exc)
4096 MONO_REQ_GC_UNSAFE_MODE;
4098 MonoClassField *field;
4099 MonoDomain *current_domain, *root_domain;
4100 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4102 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4105 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4108 current_domain = mono_domain_get ();
4109 root_domain = mono_get_root_domain ();
4111 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4112 if (current_domain != root_domain)
4113 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4115 /* set exitcode only if we will abort the process */
4116 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4117 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4118 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4120 mono_environment_exitcode_set (1);
4123 mono_print_unhandled_exception (exc);
4125 if (root_appdomain_delegate)
4126 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4127 if (current_appdomain_delegate)
4128 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4133 * mono_runtime_exec_managed_code:
4134 * @domain: Application domain
4135 * @main_func: function to invoke from the execution thread
4136 * @main_args: parameter to the main_func
4138 * Launch a new thread to execute a function
4140 * main_func is called back from the thread with main_args as the
4141 * parameter. The callback function is expected to start Main()
4142 * eventually. This function then waits for all managed threads to
4144 * It is not necesseray anymore to execute managed code in a subthread,
4145 * so this function should not be used anymore by default: just
4146 * execute the code and then call mono_thread_manage ().
4149 mono_runtime_exec_managed_code (MonoDomain *domain,
4150 MonoMainThreadFunc main_func,
4153 mono_thread_create (domain, main_func, main_args);
4155 mono_thread_manage ();
4159 * Execute a standard Main() method (args doesn't contain the
4163 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4165 MONO_REQ_GC_UNSAFE_MODE;
4170 MonoCustomAttrInfo* cinfo;
4171 gboolean has_stathread_attribute;
4172 MonoInternalThread* thread = mono_thread_internal_current ();
4178 domain = mono_object_domain (args);
4179 if (!domain->entry_assembly) {
4181 MonoAssembly *assembly;
4183 assembly = method->klass->image->assembly;
4184 domain->entry_assembly = assembly;
4185 /* Domains created from another domain already have application_base and configuration_file set */
4186 if (domain->setup->application_base == NULL) {
4187 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4190 if (domain->setup->configuration_file == NULL) {
4191 str = g_strconcat (assembly->image->name, ".config", NULL);
4192 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4194 mono_domain_set_options_from_config (domain);
4198 cinfo = mono_custom_attrs_from_method (method);
4200 static MonoClass *stathread_attribute = NULL;
4201 if (!stathread_attribute)
4202 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4203 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4205 mono_custom_attrs_free (cinfo);
4207 has_stathread_attribute = FALSE;
4209 if (has_stathread_attribute) {
4210 thread->apartment_state = ThreadApartmentState_STA;
4212 thread->apartment_state = ThreadApartmentState_MTA;
4214 mono_thread_init_apartment_state ();
4216 /* FIXME: check signature of method */
4217 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4219 res = mono_runtime_invoke (method, NULL, pa, exc);
4221 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4225 mono_environment_exitcode_set (rval);
4227 mono_runtime_invoke (method, NULL, pa, exc);
4231 /* If the return type of Main is void, only
4232 * set the exitcode if an exception was thrown
4233 * (we don't want to blow away an
4234 * explicitly-set exit code)
4237 mono_environment_exitcode_set (rval);
4245 * mono_install_runtime_invoke:
4246 * @func: Function to install
4248 * This is a VM internal routine
4251 mono_install_runtime_invoke (MonoInvokeFunc func)
4253 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4258 * mono_runtime_invoke_array:
4259 * @method: method to invoke
4260 * @obJ: object instance
4261 * @params: arguments to the method
4262 * @exc: exception information.
4264 * Invokes the method represented by @method on the object @obj.
4266 * obj is the 'this' pointer, it should be NULL for static
4267 * methods, a MonoObject* for object instances and a pointer to
4268 * the value type for value types.
4270 * The params array contains the arguments to the method with the
4271 * same convention: MonoObject* pointers for object instances and
4272 * pointers to the value type otherwise. The _invoke_array
4273 * variant takes a C# object[] as the params argument (MonoArray
4274 * *params): in this case the value types are boxed inside the
4275 * respective reference representation.
4277 * From unmanaged code you'll usually use the
4278 * mono_runtime_invoke() variant.
4280 * Note that this function doesn't handle virtual methods for
4281 * you, it will exec the exact method you pass: we still need to
4282 * expose a function to lookup the derived class implementation
4283 * of a virtual method (there are examples of this in the code,
4286 * You can pass NULL as the exc argument if you don't want to
4287 * catch exceptions, otherwise, *exc will be set to the exception
4288 * thrown, if any. if an exception is thrown, you can't use the
4289 * MonoObject* result from the function.
4291 * If the method returns a value type, it is boxed in an object
4295 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4298 MONO_REQ_GC_UNSAFE_MODE;
4300 MonoMethodSignature *sig = mono_method_signature (method);
4301 gpointer *pa = NULL;
4304 gboolean has_byref_nullables = FALSE;
4306 if (NULL != params) {
4307 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4308 for (i = 0; i < mono_array_length (params); i++) {
4309 MonoType *t = sig->params [i];
4315 case MONO_TYPE_BOOLEAN:
4318 case MONO_TYPE_CHAR:
4327 case MONO_TYPE_VALUETYPE:
4328 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4329 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4330 pa [i] = mono_array_get (params, MonoObject*, i);
4332 has_byref_nullables = TRUE;
4334 /* MS seems to create the objects if a null is passed in */
4335 if (!mono_array_get (params, MonoObject*, i))
4336 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4340 * We can't pass the unboxed vtype byref to the callee, since
4341 * that would mean the callee would be able to modify boxed
4342 * primitive types. So we (and MS) make a copy of the boxed
4343 * object, pass that to the callee, and replace the original
4344 * boxed object in the arg array with the copy.
4346 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4347 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4348 mono_array_setref (params, i, copy);
4351 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4354 case MONO_TYPE_STRING:
4355 case MONO_TYPE_OBJECT:
4356 case MONO_TYPE_CLASS:
4357 case MONO_TYPE_ARRAY:
4358 case MONO_TYPE_SZARRAY:
4360 pa [i] = mono_array_addr (params, MonoObject*, i);
4361 // FIXME: I need to check this code path
4363 pa [i] = mono_array_get (params, MonoObject*, i);
4365 case MONO_TYPE_GENERICINST:
4367 t = &t->data.generic_class->container_class->this_arg;
4369 t = &t->data.generic_class->container_class->byval_arg;
4371 case MONO_TYPE_PTR: {
4374 /* The argument should be an IntPtr */
4375 arg = mono_array_get (params, MonoObject*, i);
4379 g_assert (arg->vtable->klass == mono_defaults.int_class);
4380 pa [i] = ((MonoIntPtr*)arg)->m_value;
4385 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4390 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4393 if (mono_class_is_nullable (method->klass)) {
4394 /* Need to create a boxed vtype instead */
4400 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4404 obj = mono_object_new (mono_domain_get (), method->klass);
4405 g_assert (obj); /*maybe we should raise a TLE instead?*/
4406 #ifndef DISABLE_REMOTING
4407 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4408 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4411 if (method->klass->valuetype)
4412 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4415 } else if (method->klass->valuetype) {
4416 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4419 mono_runtime_invoke (method, o, pa, exc);
4420 return (MonoObject *)obj;
4422 if (mono_class_is_nullable (method->klass)) {
4423 MonoObject *nullable;
4425 /* Convert the unboxed vtype into a Nullable structure */
4426 nullable = mono_object_new (mono_domain_get (), method->klass);
4428 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4429 obj = mono_object_unbox (nullable);
4432 /* obj must be already unboxed if needed */
4433 res = mono_runtime_invoke (method, obj, pa, exc);
4435 if (sig->ret->type == MONO_TYPE_PTR) {
4436 MonoClass *pointer_class;
4437 static MonoMethod *box_method;
4439 MonoObject *box_exc;
4442 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4443 * convert it to a Pointer object.
4445 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4447 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4449 g_assert (res->vtable->klass == mono_defaults.int_class);
4450 box_args [0] = ((MonoIntPtr*)res)->m_value;
4451 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4452 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4453 g_assert (!box_exc);
4456 if (has_byref_nullables) {
4458 * The runtime invoke wrapper already converted byref nullables back,
4459 * and stored them in pa, we just need to copy them back to the
4462 for (i = 0; i < mono_array_length (params); i++) {
4463 MonoType *t = sig->params [i];
4465 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4466 mono_array_setref (params, i, pa [i]);
4475 arith_overflow (void)
4477 MONO_REQ_GC_UNSAFE_MODE;
4479 mono_raise_exception (mono_get_exception_overflow ());
4484 * @klass: the class of the object that we want to create
4486 * Returns: a newly created object whose definition is
4487 * looked up using @klass. This will not invoke any constructors,
4488 * so the consumer of this routine has to invoke any constructors on
4489 * its own to initialize the object.
4491 * It returns NULL on failure.
4494 mono_object_new (MonoDomain *domain, MonoClass *klass)
4496 MONO_REQ_GC_UNSAFE_MODE;
4500 vtable = mono_class_vtable (domain, klass);
4505 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4506 mono_error_raise_exception (&error); /* FIXME don't raise here */
4512 * mono_object_new_pinned:
4514 * Same as mono_object_new, but the returned object will be pinned.
4515 * For SGEN, these objects will only be freed at appdomain unload.
4518 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4520 MONO_REQ_GC_UNSAFE_MODE;
4524 vtable = mono_class_vtable (domain, klass);
4528 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4530 if (G_UNLIKELY (!o))
4531 mono_gc_out_of_memory (mono_class_instance_size (klass));
4532 else if (G_UNLIKELY (vtable->klass->has_finalize))
4533 mono_object_register_finalizer (o);
4539 * mono_object_new_specific:
4540 * @vtable: the vtable of the object that we want to create
4542 * Returns: A newly created object with class and domain specified
4546 mono_object_new_specific (MonoVTable *vtable)
4549 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4550 mono_error_raise_exception (&error);
4556 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4558 MONO_REQ_GC_UNSAFE_MODE;
4562 mono_error_init (error);
4564 /* check for is_com_object for COM Interop */
4565 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4568 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4571 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4574 mono_class_init (klass);
4576 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4578 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4581 vtable->domain->create_proxy_for_type_method = im;
4584 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4586 o = mono_runtime_invoke (im, NULL, pa, NULL);
4587 if (o != NULL) return o;
4590 return mono_object_new_alloc_specific_checked (vtable, error);
4594 ves_icall_object_new_specific (MonoVTable *vtable)
4597 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4598 mono_error_raise_exception (&error);
4604 mono_object_new_alloc_specific (MonoVTable *vtable)
4607 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4608 mono_error_raise_exception (&error);
4614 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4616 MONO_REQ_GC_UNSAFE_MODE;
4620 mono_error_init (error);
4622 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4624 if (G_UNLIKELY (!o))
4625 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4626 else if (G_UNLIKELY (vtable->klass->has_finalize))
4627 mono_object_register_finalizer (o);
4633 mono_object_new_fast (MonoVTable *vtable)
4636 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4637 mono_error_raise_exception (&error);
4643 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4645 MONO_REQ_GC_UNSAFE_MODE;
4649 mono_error_init (error);
4651 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4653 if (G_UNLIKELY (!o))
4654 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4660 ves_icall_object_new_fast (MonoVTable *vtable)
4663 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4664 mono_error_raise_exception (&error);
4670 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4672 MONO_REQ_GC_UNSAFE_MODE;
4676 mono_error_init (error);
4678 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4680 if (G_UNLIKELY (!o))
4681 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4682 else if (G_UNLIKELY (vtable->klass->has_finalize))
4683 mono_object_register_finalizer (o);
4689 * mono_class_get_allocation_ftn:
4691 * @for_box: the object will be used for boxing
4692 * @pass_size_in_words:
4694 * Return the allocation function appropriate for the given class.
4698 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4700 MONO_REQ_GC_NEUTRAL_MODE;
4702 *pass_size_in_words = FALSE;
4704 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4705 return ves_icall_object_new_specific;
4707 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4709 return ves_icall_object_new_fast;
4712 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4713 * of the overhead of parameter passing.
4716 *pass_size_in_words = TRUE;
4717 #ifdef GC_REDIRECT_TO_LOCAL
4718 return GC_local_gcj_fast_malloc;
4720 return GC_gcj_fast_malloc;
4725 return ves_icall_object_new_specific;
4729 * mono_object_new_from_token:
4730 * @image: Context where the type_token is hosted
4731 * @token: a token of the type that we want to create
4733 * Returns: A newly created object whose definition is
4734 * looked up using @token in the @image image
4737 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4739 MONO_REQ_GC_UNSAFE_MODE;
4744 klass = mono_class_get_checked (image, token, &error);
4745 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4747 return mono_object_new (domain, klass);
4752 * mono_object_clone:
4753 * @obj: the object to clone
4755 * Returns: A newly created object who is a shallow copy of @obj
4758 mono_object_clone (MonoObject *obj)
4761 MonoObject *o = mono_object_clone_checked (obj, &error);
4762 mono_error_raise_exception (&error);
4768 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4770 MONO_REQ_GC_UNSAFE_MODE;
4775 mono_error_init (error);
4777 size = obj->vtable->klass->instance_size;
4779 if (obj->vtable->klass->rank)
4780 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4782 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4784 if (G_UNLIKELY (!o)) {
4785 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4789 /* If the object doesn't contain references this will do a simple memmove. */
4790 mono_gc_wbarrier_object_copy (o, obj);
4792 if (obj->vtable->klass->has_finalize)
4793 mono_object_register_finalizer (o);
4798 * mono_array_full_copy:
4799 * @src: source array to copy
4800 * @dest: destination array
4802 * Copies the content of one array to another with exactly the same type and size.
4805 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4807 MONO_REQ_GC_UNSAFE_MODE;
4810 MonoClass *klass = src->obj.vtable->klass;
4812 g_assert (klass == dest->obj.vtable->klass);
4814 size = mono_array_length (src);
4815 g_assert (size == mono_array_length (dest));
4816 size *= mono_array_element_size (klass);
4818 if (klass->element_class->valuetype) {
4819 if (klass->element_class->has_references)
4820 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4822 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4824 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4827 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4832 * mono_array_clone_in_domain:
4833 * @domain: the domain in which the array will be cloned into
4834 * @array: the array to clone
4836 * This routine returns a copy of the array that is hosted on the
4837 * specified MonoDomain.
4840 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4842 MONO_REQ_GC_UNSAFE_MODE;
4847 MonoClass *klass = array->obj.vtable->klass;
4849 if (array->bounds == NULL) {
4850 size = mono_array_length (array);
4851 o = mono_array_new_full (domain, klass, &size, NULL);
4853 size *= mono_array_element_size (klass);
4855 if (klass->element_class->valuetype) {
4856 if (klass->element_class->has_references)
4857 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4859 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4861 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4864 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4869 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4870 size = mono_array_element_size (klass);
4871 for (i = 0; i < klass->rank; ++i) {
4872 sizes [i] = array->bounds [i].length;
4873 size *= array->bounds [i].length;
4874 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4876 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4878 if (klass->element_class->valuetype) {
4879 if (klass->element_class->has_references)
4880 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4882 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4884 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4887 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4895 * @array: the array to clone
4897 * Returns: A newly created array who is a shallow copy of @array
4900 mono_array_clone (MonoArray *array)
4902 MONO_REQ_GC_UNSAFE_MODE;
4904 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4907 /* helper macros to check for overflow when calculating the size of arrays */
4908 #ifdef MONO_BIG_ARRAYS
4909 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4910 #define MYGUINT_MAX MYGUINT64_MAX
4911 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4912 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4913 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4914 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4915 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4917 #define MYGUINT32_MAX 4294967295U
4918 #define MYGUINT_MAX MYGUINT32_MAX
4919 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4920 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4921 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4922 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4923 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4927 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4929 MONO_REQ_GC_NEUTRAL_MODE;
4933 byte_len = mono_array_element_size (klass);
4934 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4937 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4939 byte_len += MONO_SIZEOF_MONO_ARRAY;
4947 * mono_array_new_full:
4948 * @domain: domain where the object is created
4949 * @array_class: array class
4950 * @lengths: lengths for each dimension in the array
4951 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4953 * This routine creates a new array objects with the given dimensions,
4954 * lower bounds and type.
4957 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4959 MONO_REQ_GC_UNSAFE_MODE;
4961 uintptr_t byte_len = 0, len, bounds_size;
4964 MonoArrayBounds *bounds;
4968 if (!array_class->inited)
4969 mono_class_init (array_class);
4973 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4974 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4976 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4980 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4982 for (i = 0; i < array_class->rank; ++i) {
4983 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4985 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4986 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4991 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4992 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4996 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4997 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4998 byte_len = (byte_len + 3) & ~3;
4999 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
5000 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
5001 byte_len += bounds_size;
5004 * Following three lines almost taken from mono_object_new ():
5005 * they need to be kept in sync.
5007 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5009 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5011 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5013 if (G_UNLIKELY (!o))
5014 mono_gc_out_of_memory (byte_len);
5016 array = (MonoArray*)o;
5018 bounds = array->bounds;
5021 for (i = 0; i < array_class->rank; ++i) {
5022 bounds [i].length = lengths [i];
5024 bounds [i].lower_bound = lower_bounds [i];
5033 * @domain: domain where the object is created
5034 * @eclass: element class
5035 * @n: number of array elements
5037 * This routine creates a new szarray with @n elements of type @eclass.
5040 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5042 MONO_REQ_GC_UNSAFE_MODE;
5046 ac = mono_array_class_get (eclass, 1);
5049 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
5053 * mono_array_new_specific:
5054 * @vtable: a vtable in the appropriate domain for an initialized class
5055 * @n: number of array elements
5057 * This routine is a fast alternative to mono_array_new() for code which
5058 * can be sure about the domain it operates in.
5061 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5063 MONO_REQ_GC_UNSAFE_MODE;
5068 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5073 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5074 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
5077 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5079 if (G_UNLIKELY (!o))
5080 mono_gc_out_of_memory (byte_len);
5082 return (MonoArray*)o;
5086 * mono_string_new_utf16:
5087 * @text: a pointer to an utf16 string
5088 * @len: the length of the string
5090 * Returns: A newly created string object which contains @text.
5093 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5095 MONO_REQ_GC_UNSAFE_MODE;
5099 s = mono_string_new_size (domain, len);
5100 g_assert (s != NULL);
5102 memcpy (mono_string_chars (s), text, len * 2);
5108 * mono_string_new_utf32:
5109 * @text: a pointer to an utf32 string
5110 * @len: the length of the string
5112 * Returns: A newly created string object which contains @text.
5115 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5117 MONO_REQ_GC_UNSAFE_MODE;
5120 mono_unichar2 *utf16_output = NULL;
5121 gint32 utf16_len = 0;
5122 GError *error = NULL;
5123 glong items_written;
5125 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5128 g_error_free (error);
5130 while (utf16_output [utf16_len]) utf16_len++;
5132 s = mono_string_new_size (domain, utf16_len);
5133 g_assert (s != NULL);
5135 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5137 g_free (utf16_output);
5143 * mono_string_new_size:
5144 * @text: a pointer to an utf16 string
5145 * @len: the length of the string
5147 * Returns: A newly created string object of @len
5150 mono_string_new_size (MonoDomain *domain, gint32 len)
5152 MONO_REQ_GC_UNSAFE_MODE;
5158 /* check for overflow */
5159 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5160 mono_gc_out_of_memory (-1);
5162 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5163 g_assert (size > 0);
5165 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5168 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5170 if (G_UNLIKELY (!s))
5171 mono_gc_out_of_memory (size);
5177 * mono_string_new_len:
5178 * @text: a pointer to an utf8 string
5179 * @length: number of bytes in @text to consider
5181 * Returns: A newly created string object which contains @text.
5184 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5186 MONO_REQ_GC_UNSAFE_MODE;
5188 GError *error = NULL;
5189 MonoString *o = NULL;
5191 glong items_written;
5193 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5196 o = mono_string_new_utf16 (domain, ut, items_written);
5198 g_error_free (error);
5207 * @text: a pointer to an utf8 string
5209 * Returns: A newly created string object which contains @text.
5212 mono_string_new (MonoDomain *domain, const char *text)
5214 MONO_REQ_GC_UNSAFE_MODE;
5216 GError *error = NULL;
5217 MonoString *o = NULL;
5219 glong items_written;
5224 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5227 o = mono_string_new_utf16 (domain, ut, items_written);
5229 g_error_free (error);
5232 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5237 MonoString *o = NULL;
5239 if (!g_utf8_validate (text, -1, &end))
5242 len = g_utf8_strlen (text, -1);
5243 o = mono_string_new_size (domain, len);
5244 str = mono_string_chars (o);
5246 while (text < end) {
5247 *str++ = g_utf8_get_char (text);
5248 text = g_utf8_next_char (text);
5255 * mono_string_new_wrapper:
5256 * @text: pointer to utf8 characters.
5258 * Helper function to create a string object from @text in the current domain.
5261 mono_string_new_wrapper (const char *text)
5263 MONO_REQ_GC_UNSAFE_MODE;
5265 MonoDomain *domain = mono_domain_get ();
5268 return mono_string_new (domain, text);
5275 * @class: the class of the value
5276 * @value: a pointer to the unboxed data
5278 * Returns: A newly created object which contains @value.
5281 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5283 MONO_REQ_GC_UNSAFE_MODE;
5290 g_assert (klass->valuetype);
5291 if (mono_class_is_nullable (klass))
5292 return mono_nullable_box ((guint8 *)value, klass);
5294 vtable = mono_class_vtable (domain, klass);
5297 size = mono_class_instance_size (klass);
5298 res = mono_object_new_alloc_specific_checked (vtable, &error);
5299 mono_error_raise_exception (&error); /* FIXME don't raise here */
5301 size = size - sizeof (MonoObject);
5304 g_assert (size == mono_class_value_size (klass, NULL));
5305 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5307 #if NO_UNALIGNED_ACCESS
5308 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5312 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5315 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5318 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5321 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5324 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5328 if (klass->has_finalize)
5329 mono_object_register_finalizer (res);
5335 * @dest: destination pointer
5336 * @src: source pointer
5337 * @klass: a valuetype class
5339 * Copy a valuetype from @src to @dest. This function must be used
5340 * when @klass contains references fields.
5343 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5345 MONO_REQ_GC_UNSAFE_MODE;
5347 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5351 * mono_value_copy_array:
5352 * @dest: destination array
5353 * @dest_idx: index in the @dest array
5354 * @src: source pointer
5355 * @count: number of items
5357 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5358 * This function must be used when @klass contains references fields.
5359 * Overlap is handled.
5362 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5364 MONO_REQ_GC_UNSAFE_MODE;
5366 int size = mono_array_element_size (dest->obj.vtable->klass);
5367 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5368 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5369 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5373 * mono_object_get_domain:
5374 * @obj: object to query
5376 * Returns: the MonoDomain where the object is hosted
5379 mono_object_get_domain (MonoObject *obj)
5381 MONO_REQ_GC_UNSAFE_MODE;
5383 return mono_object_domain (obj);
5387 * mono_object_get_class:
5388 * @obj: object to query
5390 * Returns: the MonOClass of the object.
5393 mono_object_get_class (MonoObject *obj)
5395 MONO_REQ_GC_UNSAFE_MODE;
5397 return mono_object_class (obj);
5400 * mono_object_get_size:
5401 * @o: object to query
5403 * Returns: the size, in bytes, of @o
5406 mono_object_get_size (MonoObject* o)
5408 MONO_REQ_GC_UNSAFE_MODE;
5410 MonoClass* klass = mono_object_class (o);
5411 if (klass == mono_defaults.string_class) {
5412 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5413 } else if (o->vtable->rank) {
5414 MonoArray *array = (MonoArray*)o;
5415 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5416 if (array->bounds) {
5419 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5423 return mono_class_instance_size (klass);
5428 * mono_object_unbox:
5429 * @obj: object to unbox
5431 * Returns: a pointer to the start of the valuetype boxed in this
5434 * This method will assert if the object passed is not a valuetype.
5437 mono_object_unbox (MonoObject *obj)
5439 MONO_REQ_GC_UNSAFE_MODE;
5441 /* add assert for valuetypes? */
5442 g_assert (obj->vtable->klass->valuetype);
5443 return ((char*)obj) + sizeof (MonoObject);
5447 * mono_object_isinst:
5449 * @klass: a pointer to a class
5451 * Returns: @obj if @obj is derived from @klass
5454 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5456 MONO_REQ_GC_UNSAFE_MODE;
5459 mono_class_init (klass);
5461 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5462 return mono_object_isinst_mbyref (obj, klass);
5467 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5471 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5473 MONO_REQ_GC_UNSAFE_MODE;
5482 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5483 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5487 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5488 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5491 MonoClass *oklass = vt->klass;
5492 if (mono_class_is_transparent_proxy (oklass))
5493 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5495 mono_class_setup_supertypes (klass);
5496 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5499 #ifndef DISABLE_REMOTING
5500 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5502 MonoDomain *domain = mono_domain_get ();
5504 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5505 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5506 MonoMethod *im = NULL;
5509 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5511 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5512 im = mono_object_get_virtual_method (rp, im);
5515 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5518 res = mono_runtime_invoke (im, rp, pa, NULL);
5520 if (*(MonoBoolean *) mono_object_unbox(res)) {
5521 /* Update the vtable of the remote type, so it can safely cast to this new type */
5522 mono_upgrade_remote_class (domain, obj, klass);
5526 #endif /* DISABLE_REMOTING */
5531 * mono_object_castclass_mbyref:
5533 * @klass: a pointer to a class
5535 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5538 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5540 MONO_REQ_GC_UNSAFE_MODE;
5542 if (!obj) return NULL;
5543 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5545 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5547 "InvalidCastException"));
5552 MonoDomain *orig_domain;
5558 str_lookup (MonoDomain *domain, gpointer user_data)
5560 MONO_REQ_GC_UNSAFE_MODE;
5562 LDStrInfo *info = (LDStrInfo *)user_data;
5563 if (info->res || domain == info->orig_domain)
5565 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5569 mono_string_get_pinned (MonoString *str, MonoError *error)
5571 MONO_REQ_GC_UNSAFE_MODE;
5573 mono_error_init (error);
5575 /* We only need to make a pinned version of a string if this is a moving GC */
5576 if (!mono_gc_is_moving ())
5580 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5581 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5583 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5584 news->length = mono_string_length (str);
5586 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5592 mono_string_is_interned_lookup (MonoString *str, int insert)
5594 MONO_REQ_GC_UNSAFE_MODE;
5597 MonoGHashTable *ldstr_table;
5598 MonoString *s, *res;
5601 domain = ((MonoObject *)str)->vtable->domain;
5602 ldstr_table = domain->ldstr_table;
5604 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5610 /* Allocate outside the lock */
5612 s = mono_string_get_pinned (str, &error);
5613 mono_error_raise_exception (&error); /* FIXME don't raise here */
5616 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5621 mono_g_hash_table_insert (ldstr_table, s, s);
5626 LDStrInfo ldstr_info;
5627 ldstr_info.orig_domain = domain;
5628 ldstr_info.ins = str;
5629 ldstr_info.res = NULL;
5631 mono_domain_foreach (str_lookup, &ldstr_info);
5632 if (ldstr_info.res) {
5634 * the string was already interned in some other domain:
5635 * intern it in the current one as well.
5637 mono_g_hash_table_insert (ldstr_table, str, str);
5647 * mono_string_is_interned:
5648 * @o: String to probe
5650 * Returns whether the string has been interned.
5653 mono_string_is_interned (MonoString *o)
5655 MONO_REQ_GC_UNSAFE_MODE;
5657 return mono_string_is_interned_lookup (o, FALSE);
5661 * mono_string_intern:
5662 * @o: String to intern
5664 * Interns the string passed.
5665 * Returns: The interned string.
5668 mono_string_intern (MonoString *str)
5670 MONO_REQ_GC_UNSAFE_MODE;
5672 return mono_string_is_interned_lookup (str, TRUE);
5677 * @domain: the domain where the string will be used.
5678 * @image: a metadata context
5679 * @idx: index into the user string table.
5681 * Implementation for the ldstr opcode.
5682 * Returns: a loaded string from the @image/@idx combination.
5685 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5687 MONO_REQ_GC_UNSAFE_MODE;
5689 if (image->dynamic) {
5690 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5693 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5694 return NULL; /*FIXME we should probably be raising an exception here*/
5695 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5700 * mono_ldstr_metadata_sig
5701 * @domain: the domain for the string
5702 * @sig: the signature of a metadata string
5704 * Returns: a MonoString for a string stored in the metadata
5707 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5709 MONO_REQ_GC_UNSAFE_MODE;
5712 const char *str = sig;
5713 MonoString *o, *interned;
5716 len2 = mono_metadata_decode_blob_size (str, &str);
5719 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5720 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5723 guint16 *p2 = (guint16*)mono_string_chars (o);
5724 for (i = 0; i < len2; ++i) {
5725 *p2 = GUINT16_FROM_LE (*p2);
5731 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5734 return interned; /* o will get garbage collected */
5736 o = mono_string_get_pinned (o, &error);
5737 mono_error_raise_exception (&error); /* FIXME don't raise here */
5740 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5742 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5752 * mono_string_to_utf8:
5753 * @s: a System.String
5755 * Returns the UTF8 representation for @s.
5756 * The resulting buffer needs to be freed with mono_free().
5758 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5761 mono_string_to_utf8 (MonoString *s)
5763 MONO_REQ_GC_UNSAFE_MODE;
5766 char *result = mono_string_to_utf8_checked (s, &error);
5768 if (!mono_error_ok (&error))
5769 mono_error_raise_exception (&error);
5774 * mono_string_to_utf8_checked:
5775 * @s: a System.String
5776 * @error: a MonoError.
5778 * Converts a MonoString to its UTF8 representation. May fail; check
5779 * @error to determine whether the conversion was successful.
5780 * The resulting buffer should be freed with mono_free().
5783 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5785 MONO_REQ_GC_UNSAFE_MODE;
5789 GError *gerror = NULL;
5791 mono_error_init (error);
5797 return g_strdup ("");
5799 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5801 mono_error_set_argument (error, "string", "%s", gerror->message);
5802 g_error_free (gerror);
5805 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5806 if (s->length > written) {
5807 /* allocate the total length and copy the part of the string that has been converted */
5808 char *as2 = (char *)g_malloc0 (s->length);
5809 memcpy (as2, as, written);
5818 * mono_string_to_utf8_ignore:
5821 * Converts a MonoString to its UTF8 representation. Will ignore
5822 * invalid surrogate pairs.
5823 * The resulting buffer should be freed with mono_free().
5827 mono_string_to_utf8_ignore (MonoString *s)
5829 MONO_REQ_GC_UNSAFE_MODE;
5838 return g_strdup ("");
5840 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5842 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5843 if (s->length > written) {
5844 /* allocate the total length and copy the part of the string that has been converted */
5845 char *as2 = (char *)g_malloc0 (s->length);
5846 memcpy (as2, as, written);
5855 * mono_string_to_utf8_image_ignore:
5856 * @s: a System.String
5858 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5861 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5863 MONO_REQ_GC_UNSAFE_MODE;
5865 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5869 * mono_string_to_utf8_mp_ignore:
5870 * @s: a System.String
5872 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5875 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5877 MONO_REQ_GC_UNSAFE_MODE;
5879 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5884 * mono_string_to_utf16:
5887 * Return an null-terminated array of the utf-16 chars
5888 * contained in @s. The result must be freed with g_free().
5889 * This is a temporary helper until our string implementation
5890 * is reworked to always include the null terminating char.
5893 mono_string_to_utf16 (MonoString *s)
5895 MONO_REQ_GC_UNSAFE_MODE;
5902 as = (char *)g_malloc ((s->length * 2) + 2);
5903 as [(s->length * 2)] = '\0';
5904 as [(s->length * 2) + 1] = '\0';
5907 return (gunichar2 *)(as);
5910 memcpy (as, mono_string_chars(s), s->length * 2);
5911 return (gunichar2 *)(as);
5915 * mono_string_to_utf32:
5918 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5919 * contained in @s. The result must be freed with g_free().
5922 mono_string_to_utf32 (MonoString *s)
5924 MONO_REQ_GC_UNSAFE_MODE;
5926 mono_unichar4 *utf32_output = NULL;
5927 GError *error = NULL;
5928 glong items_written;
5933 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5936 g_error_free (error);
5938 return utf32_output;
5942 * mono_string_from_utf16:
5943 * @data: the UTF16 string (LPWSTR) to convert
5945 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5947 * Returns: a MonoString.
5950 mono_string_from_utf16 (gunichar2 *data)
5952 MONO_REQ_GC_UNSAFE_MODE;
5954 MonoDomain *domain = mono_domain_get ();
5960 while (data [len]) len++;
5962 return mono_string_new_utf16 (domain, data, len);
5966 * mono_string_from_utf32:
5967 * @data: the UTF32 string (LPWSTR) to convert
5969 * Converts a UTF32 (UCS-4)to a MonoString.
5971 * Returns: a MonoString.
5974 mono_string_from_utf32 (mono_unichar4 *data)
5976 MONO_REQ_GC_UNSAFE_MODE;
5978 MonoString* result = NULL;
5979 mono_unichar2 *utf16_output = NULL;
5980 GError *error = NULL;
5981 glong items_written;
5987 while (data [len]) len++;
5989 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5992 g_error_free (error);
5994 result = mono_string_from_utf16 (utf16_output);
5995 g_free (utf16_output);
6000 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6002 MONO_REQ_GC_UNSAFE_MODE;
6009 r = mono_string_to_utf8_ignore (s);
6011 r = mono_string_to_utf8_checked (s, error);
6012 if (!mono_error_ok (error))
6019 len = strlen (r) + 1;
6021 mp_s = (char *)mono_mempool_alloc (mp, len);
6023 mp_s = (char *)mono_image_alloc (image, len);
6025 memcpy (mp_s, r, len);
6033 * mono_string_to_utf8_image:
6034 * @s: a System.String
6036 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6039 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6041 MONO_REQ_GC_UNSAFE_MODE;
6043 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6047 * mono_string_to_utf8_mp:
6048 * @s: a System.String
6050 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6053 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6055 MONO_REQ_GC_UNSAFE_MODE;
6057 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6061 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6064 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6066 eh_callbacks = *cbs;
6069 MonoRuntimeExceptionHandlingCallbacks *
6070 mono_get_eh_callbacks (void)
6072 return &eh_callbacks;
6076 * mono_raise_exception:
6077 * @ex: exception object
6079 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6082 mono_raise_exception (MonoException *ex)
6084 MONO_REQ_GC_UNSAFE_MODE;
6087 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6088 * that will cause gcc to omit the function epilog, causing problems when
6089 * the JIT tries to walk the stack, since the return address on the stack
6090 * will point into the next function in the executable, not this one.
6092 eh_callbacks.mono_raise_exception (ex);
6096 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6098 MONO_REQ_GC_UNSAFE_MODE;
6100 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6104 * mono_wait_handle_new:
6105 * @domain: Domain where the object will be created
6106 * @handle: Handle for the wait handle
6108 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6111 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6113 MONO_REQ_GC_UNSAFE_MODE;
6115 MonoWaitHandle *res;
6116 gpointer params [1];
6117 static MonoMethod *handle_set;
6119 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6121 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6123 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6125 params [0] = &handle;
6126 mono_runtime_invoke (handle_set, res, params, NULL);
6132 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6134 MONO_REQ_GC_UNSAFE_MODE;
6136 static MonoClassField *f_os_handle;
6137 static MonoClassField *f_safe_handle;
6139 if (!f_os_handle && !f_safe_handle) {
6140 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6141 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6146 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6150 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6157 mono_runtime_capture_context (MonoDomain *domain)
6159 MONO_REQ_GC_UNSAFE_MODE;
6161 RuntimeInvokeFunction runtime_invoke;
6163 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6164 MonoMethod *method = mono_get_context_capture_method ();
6165 MonoMethod *wrapper;
6168 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6169 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6170 domain->capture_context_method = mono_compile_method (method);
6173 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6175 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6178 * mono_async_result_new:
6179 * @domain:domain where the object will be created.
6180 * @handle: wait handle.
6181 * @state: state to pass to AsyncResult
6182 * @data: C closure data.
6184 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6185 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6189 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6191 MONO_REQ_GC_UNSAFE_MODE;
6193 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6194 MonoObject *context = mono_runtime_capture_context (domain);
6195 /* we must capture the execution context from the original thread */
6197 MONO_OBJECT_SETREF (res, execution_context, context);
6198 /* note: result may be null if the flow is suppressed */
6201 res->data = (void **)data;
6202 MONO_OBJECT_SETREF (res, object_data, object_data);
6203 MONO_OBJECT_SETREF (res, async_state, state);
6205 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6207 res->sync_completed = FALSE;
6208 res->completed = FALSE;
6214 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6216 MONO_REQ_GC_UNSAFE_MODE;
6222 g_assert (ares->async_delegate);
6224 ac = (MonoAsyncCall*) ares->object_data;
6226 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6228 gpointer wait_event = NULL;
6230 ac->msg->exc = NULL;
6231 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6232 MONO_OBJECT_SETREF (ac, res, res);
6234 mono_monitor_enter ((MonoObject*) ares);
6235 ares->completed = 1;
6237 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6238 mono_monitor_exit ((MonoObject*) ares);
6240 if (wait_event != NULL)
6241 SetEvent (wait_event);
6243 if (ac->cb_method) {
6244 /* we swallow the excepton as it is the behavior on .NET */
6245 MonoObject *exc = NULL;
6246 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6248 mono_unhandled_exception (exc);
6256 mono_message_init (MonoDomain *domain,
6257 MonoMethodMessage *this_obj,
6258 MonoReflectionMethod *method,
6259 MonoArray *out_args)
6261 MONO_REQ_GC_UNSAFE_MODE;
6263 static MonoClass *object_array_klass;
6264 static MonoClass *byte_array_klass;
6265 static MonoClass *string_array_klass;
6266 MonoMethodSignature *sig = mono_method_signature (method->method);
6272 if (!object_array_klass) {
6275 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6277 byte_array_klass = klass;
6279 klass = mono_array_class_get (mono_defaults.string_class, 1);
6281 string_array_klass = klass;
6283 klass = mono_array_class_get (mono_defaults.object_class, 1);
6286 mono_atomic_store_release (&object_array_klass, klass);
6289 MONO_OBJECT_SETREF (this_obj, method, method);
6291 MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6292 MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6293 this_obj->async_result = NULL;
6294 this_obj->call_type = CallType_Sync;
6296 names = g_new (char *, sig->param_count);
6297 mono_method_get_param_names (method->method, (const char **) names);
6298 MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6300 for (i = 0; i < sig->param_count; i++) {
6301 name = mono_string_new (domain, names [i]);
6302 mono_array_setref (this_obj->names, i, name);
6306 for (i = 0, j = 0; i < sig->param_count; i++) {
6307 if (sig->params [i]->byref) {
6309 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6310 mono_array_setref (this_obj->args, i, arg);
6314 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6318 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6321 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6325 #ifndef DISABLE_REMOTING
6327 * mono_remoting_invoke:
6328 * @real_proxy: pointer to a RealProxy object
6329 * @msg: The MonoMethodMessage to execute
6330 * @exc: used to store exceptions
6331 * @out_args: used to store output arguments
6333 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6334 * IMessage interface and it is not trivial to extract results from there. So
6335 * we call an helper method PrivateInvoke instead of calling
6336 * RealProxy::Invoke() directly.
6338 * Returns: the result object.
6341 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6342 MonoObject **exc, MonoArray **out_args)
6344 MONO_REQ_GC_UNSAFE_MODE;
6346 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6349 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6352 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6354 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6355 real_proxy->vtable->domain->private_invoke_method = im;
6358 pa [0] = real_proxy;
6363 return mono_runtime_invoke (im, NULL, pa, exc);
6368 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6369 MonoObject **exc, MonoArray **out_args)
6371 MONO_REQ_GC_UNSAFE_MODE;
6373 static MonoClass *object_array_klass;
6376 MonoMethodSignature *sig;
6378 int i, j, outarg_count = 0;
6380 #ifndef DISABLE_REMOTING
6381 if (target && mono_object_is_transparent_proxy (target)) {
6382 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6383 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6384 target = tp->rp->unwrapped_server;
6386 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6391 domain = mono_domain_get ();
6392 method = msg->method->method;
6393 sig = mono_method_signature (method);
6395 for (i = 0; i < sig->param_count; i++) {
6396 if (sig->params [i]->byref)
6400 if (!object_array_klass) {
6403 klass = mono_array_class_get (mono_defaults.object_class, 1);
6406 mono_memory_barrier ();
6407 object_array_klass = klass;
6410 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6413 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6415 for (i = 0, j = 0; i < sig->param_count; i++) {
6416 if (sig->params [i]->byref) {
6418 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6419 mono_array_setref (*out_args, j, arg);
6428 * mono_object_to_string:
6430 * @exc: Any exception thrown by ToString (). May be NULL.
6432 * Returns: the result of calling ToString () on an object.
6435 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6437 MONO_REQ_GC_UNSAFE_MODE;
6439 static MonoMethod *to_string = NULL;
6446 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6448 method = mono_object_get_virtual_method (obj, to_string);
6450 // Unbox value type if needed
6451 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6452 target = mono_object_unbox (obj);
6455 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6459 * mono_print_unhandled_exception:
6460 * @exc: The exception
6462 * Prints the unhandled exception.
6465 mono_print_unhandled_exception (MonoObject *exc)
6467 MONO_REQ_GC_UNSAFE_MODE;
6470 char *message = (char*)"";
6471 gboolean free_message = FALSE;
6474 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6475 message = g_strdup ("OutOfMemoryException");
6476 free_message = TRUE;
6477 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6478 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6479 free_message = TRUE;
6482 if (((MonoException*)exc)->native_trace_ips) {
6483 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6484 free_message = TRUE;
6486 MonoObject *other_exc = NULL;
6487 str = mono_object_to_string (exc, &other_exc);
6489 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6490 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6492 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6493 original_backtrace, nested_backtrace);
6495 g_free (original_backtrace);
6496 g_free (nested_backtrace);
6497 free_message = TRUE;
6499 message = mono_string_to_utf8_checked (str, &error);
6500 if (!mono_error_ok (&error)) {
6501 mono_error_cleanup (&error);
6502 message = (char *) "";
6504 free_message = TRUE;
6511 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6512 * exc->vtable->klass->name, message);
6514 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6521 * mono_delegate_ctor:
6522 * @this: pointer to an uninitialized delegate object
6523 * @target: target object
6524 * @addr: pointer to native code
6527 * Initialize a delegate and sets a specific method, not the one
6528 * associated with addr. This is useful when sharing generic code.
6529 * In that case addr will most probably not be associated with the
6530 * correct instantiation of the method.
6533 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6535 MONO_REQ_GC_UNSAFE_MODE;
6537 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6539 g_assert (this_obj);
6542 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6545 delegate->method = method;
6547 mono_stats.delegate_creations++;
6549 #ifndef DISABLE_REMOTING
6550 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6552 method = mono_marshal_get_remoting_invoke (method);
6553 delegate->method_ptr = mono_compile_method (method);
6554 MONO_OBJECT_SETREF (delegate, target, target);
6558 delegate->method_ptr = addr;
6559 MONO_OBJECT_SETREF (delegate, target, target);
6562 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6563 if (callbacks.init_delegate)
6564 callbacks.init_delegate (delegate);
6568 * mono_delegate_ctor:
6569 * @this: pointer to an uninitialized delegate object
6570 * @target: target object
6571 * @addr: pointer to native code
6573 * This is used to initialize a delegate.
6576 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6578 MONO_REQ_GC_UNSAFE_MODE;
6580 MonoDomain *domain = mono_domain_get ();
6582 MonoMethod *method = NULL;
6586 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6588 if (!ji && domain != mono_get_root_domain ())
6589 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6591 method = mono_jit_info_get_method (ji);
6592 g_assert (!method->klass->generic_container);
6595 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6599 * mono_method_call_message_new:
6600 * @method: method to encapsulate
6601 * @params: parameters to the method
6602 * @invoke: optional, delegate invoke.
6603 * @cb: async callback delegate.
6604 * @state: state passed to the async callback.
6606 * Translates arguments pointers into a MonoMethodMessage.
6609 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6610 MonoDelegate **cb, MonoObject **state)
6612 MONO_REQ_GC_UNSAFE_MODE;
6614 MonoDomain *domain = mono_domain_get ();
6615 MonoMethodSignature *sig = mono_method_signature (method);
6616 MonoMethodMessage *msg;
6619 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6622 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6623 count = sig->param_count - 2;
6625 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6626 count = sig->param_count;
6629 for (i = 0; i < count; i++) {
6634 if (sig->params [i]->byref)
6635 vpos = *((gpointer *)params [i]);
6639 klass = mono_class_from_mono_type (sig->params [i]);
6641 if (klass->valuetype)
6642 arg = mono_value_box (domain, klass, vpos);
6644 arg = *((MonoObject **)vpos);
6646 mono_array_setref (msg->args, i, arg);
6649 if (cb != NULL && state != NULL) {
6650 *cb = *((MonoDelegate **)params [i]);
6652 *state = *((MonoObject **)params [i]);
6659 * mono_method_return_message_restore:
6661 * Restore results from message based processing back to arguments pointers
6664 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6666 MONO_REQ_GC_UNSAFE_MODE;
6668 MonoMethodSignature *sig = mono_method_signature (method);
6669 int i, j, type, size, out_len;
6671 if (out_args == NULL)
6673 out_len = mono_array_length (out_args);
6677 for (i = 0, j = 0; i < sig->param_count; i++) {
6678 MonoType *pt = sig->params [i];
6683 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6685 arg = (char *)mono_array_get (out_args, gpointer, j);
6688 g_assert (type != MONO_TYPE_VOID);
6690 if (MONO_TYPE_IS_REFERENCE (pt)) {
6691 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6694 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6695 size = mono_class_value_size (klass, NULL);
6696 if (klass->has_references)
6697 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6699 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6701 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6702 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6711 #ifndef DISABLE_REMOTING
6714 * mono_load_remote_field:
6715 * @this: pointer to an object
6716 * @klass: klass of the object containing @field
6717 * @field: the field to load
6718 * @res: a storage to store the result
6720 * This method is called by the runtime on attempts to load fields of
6721 * transparent proxy objects. @this points to such TP, @klass is the class of
6722 * the object containing @field. @res is a storage location which can be
6723 * used to store the result.
6725 * Returns: an address pointing to the value of field.
6728 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6730 MONO_REQ_GC_UNSAFE_MODE;
6732 static MonoMethod *getter = NULL;
6733 MonoDomain *domain = mono_domain_get ();
6734 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6735 MonoClass *field_class;
6736 MonoMethodMessage *msg;
6737 MonoArray *out_args;
6741 g_assert (mono_object_is_transparent_proxy (this_obj));
6742 g_assert (res != NULL);
6744 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6745 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6750 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6752 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6755 field_class = mono_class_from_mono_type (field->type);
6757 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6758 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6759 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6761 full_name = mono_type_get_full_name (klass);
6762 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6763 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6766 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6768 if (exc) mono_raise_exception ((MonoException *)exc);
6770 if (mono_array_length (out_args) == 0)
6773 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6775 if (field_class->valuetype) {
6776 return ((char *)*res) + sizeof (MonoObject);
6782 * mono_load_remote_field_new:
6787 * Missing documentation.
6790 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6792 MONO_REQ_GC_UNSAFE_MODE;
6794 static MonoMethod *getter = NULL;
6795 MonoDomain *domain = mono_domain_get ();
6796 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6797 MonoClass *field_class;
6798 MonoMethodMessage *msg;
6799 MonoArray *out_args;
6800 MonoObject *exc, *res;
6803 g_assert (mono_object_is_transparent_proxy (this_obj));
6805 field_class = mono_class_from_mono_type (field->type);
6807 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6809 if (field_class->valuetype) {
6810 res = mono_object_new (domain, field_class);
6811 val = ((gchar *) res) + sizeof (MonoObject);
6815 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6820 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6822 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6825 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6826 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6828 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6830 full_name = mono_type_get_full_name (klass);
6831 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6832 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6835 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6837 if (exc) mono_raise_exception ((MonoException *)exc);
6839 if (mono_array_length (out_args) == 0)
6842 res = mono_array_get (out_args, MonoObject *, 0);
6848 * mono_store_remote_field:
6849 * @this_obj: pointer to an object
6850 * @klass: klass of the object containing @field
6851 * @field: the field to load
6852 * @val: the value/object to store
6854 * This method is called by the runtime on attempts to store fields of
6855 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6856 * the object containing @field. @val is the new value to store in @field.
6859 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6861 MONO_REQ_GC_UNSAFE_MODE;
6863 static MonoMethod *setter = NULL;
6864 MonoDomain *domain = mono_domain_get ();
6865 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6866 MonoClass *field_class;
6867 MonoMethodMessage *msg;
6868 MonoArray *out_args;
6873 g_assert (mono_object_is_transparent_proxy (this_obj));
6875 field_class = mono_class_from_mono_type (field->type);
6877 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6878 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6879 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6884 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6886 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6889 if (field_class->valuetype)
6890 arg = mono_value_box (domain, field_class, val);
6892 arg = *((MonoObject **)val);
6895 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6896 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6898 full_name = mono_type_get_full_name (klass);
6899 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6900 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6901 mono_array_setref (msg->args, 2, arg);
6904 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6906 if (exc) mono_raise_exception ((MonoException *)exc);
6910 * mono_store_remote_field_new:
6916 * Missing documentation
6919 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6921 MONO_REQ_GC_UNSAFE_MODE;
6923 static MonoMethod *setter = NULL;
6924 MonoDomain *domain = mono_domain_get ();
6925 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6926 MonoClass *field_class;
6927 MonoMethodMessage *msg;
6928 MonoArray *out_args;
6932 g_assert (mono_object_is_transparent_proxy (this_obj));
6934 field_class = mono_class_from_mono_type (field->type);
6936 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6937 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6938 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6943 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6945 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6948 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6949 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6951 full_name = mono_type_get_full_name (klass);
6952 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6953 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6954 mono_array_setref (msg->args, 2, arg);
6957 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6959 if (exc) mono_raise_exception ((MonoException *)exc);
6964 * mono_create_ftnptr:
6966 * Given a function address, create a function descriptor for it.
6967 * This is only needed on some platforms.
6970 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6972 return callbacks.create_ftnptr (domain, addr);
6976 * mono_get_addr_from_ftnptr:
6978 * Given a pointer to a function descriptor, return the function address.
6979 * This is only needed on some platforms.
6982 mono_get_addr_from_ftnptr (gpointer descr)
6984 return callbacks.get_addr_from_ftnptr (descr);
6988 * mono_string_chars:
6991 * Returns a pointer to the UCS16 characters stored in the MonoString
6994 mono_string_chars (MonoString *s)
6996 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7002 * mono_string_length:
7005 * Returns the lenght in characters of the string
7008 mono_string_length (MonoString *s)
7010 MONO_REQ_GC_UNSAFE_MODE;
7016 * mono_array_length:
7017 * @array: a MonoArray*
7019 * Returns the total number of elements in the array. This works for
7020 * both vectors and multidimensional arrays.
7023 mono_array_length (MonoArray *array)
7025 MONO_REQ_GC_UNSAFE_MODE;
7027 return array->max_length;
7031 * mono_array_addr_with_size:
7032 * @array: a MonoArray*
7033 * @size: size of the array elements
7034 * @idx: index into the array
7036 * Returns the address of the @idx element in the array.
7039 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7041 MONO_REQ_GC_UNSAFE_MODE;
7043 return ((char*)(array)->vector) + size * idx;
7048 mono_glist_to_array (GList *list, MonoClass *eclass)
7050 MonoDomain *domain = mono_domain_get ();
7057 len = g_list_length (list);
7058 res = mono_array_new (domain, eclass, len);
7060 for (i = 0; list; list = list->next, i++)
7061 mono_array_set (res, gpointer, i, list->data);