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 ves_icall_string_alloc (int length)
966 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
967 mono_error_raise_exception (&error);
973 mono_class_compute_gc_descriptor (MonoClass *klass)
975 MONO_REQ_GC_NEUTRAL_MODE;
979 gsize default_bitmap [4] = {0};
980 static gboolean gcj_inited = FALSE;
985 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
986 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
989 mono_loader_unlock ();
993 mono_class_init (klass);
995 if (klass->gc_descr_inited)
998 klass->gc_descr_inited = TRUE;
999 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1001 bitmap = default_bitmap;
1002 if (klass == mono_defaults.string_class) {
1003 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1004 } else if (klass->rank) {
1005 mono_class_compute_gc_descriptor (klass->element_class);
1006 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1008 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1009 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1010 class->name_space, class->name);*/
1012 /* remove the object header */
1013 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1014 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));
1015 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1016 class->name_space, class->name);*/
1017 if (bitmap != default_bitmap)
1021 /*static int count = 0;
1024 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1025 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1027 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1028 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1030 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1031 if (bitmap != default_bitmap)
1037 * field_is_special_static:
1038 * @fklass: The MonoClass to look up.
1039 * @field: The MonoClassField describing the field.
1041 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1042 * SPECIAL_STATIC_NONE otherwise.
1045 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1047 MONO_REQ_GC_NEUTRAL_MODE;
1049 MonoCustomAttrInfo *ainfo;
1051 ainfo = mono_custom_attrs_from_field (fklass, field);
1054 for (i = 0; i < ainfo->num_attrs; ++i) {
1055 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1056 if (klass->image == mono_defaults.corlib) {
1057 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1058 mono_custom_attrs_free (ainfo);
1059 return SPECIAL_STATIC_THREAD;
1061 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1062 mono_custom_attrs_free (ainfo);
1063 return SPECIAL_STATIC_CONTEXT;
1067 mono_custom_attrs_free (ainfo);
1068 return SPECIAL_STATIC_NONE;
1071 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1072 #define mix(a,b,c) { \
1073 a -= c; a ^= rot(c, 4); c += b; \
1074 b -= a; b ^= rot(a, 6); a += c; \
1075 c -= b; c ^= rot(b, 8); b += a; \
1076 a -= c; a ^= rot(c,16); c += b; \
1077 b -= a; b ^= rot(a,19); a += c; \
1078 c -= b; c ^= rot(b, 4); b += a; \
1080 #define final(a,b,c) { \
1081 c ^= b; c -= rot(b,14); \
1082 a ^= c; a -= rot(c,11); \
1083 b ^= a; b -= rot(a,25); \
1084 c ^= b; c -= rot(b,16); \
1085 a ^= c; a -= rot(c,4); \
1086 b ^= a; b -= rot(a,14); \
1087 c ^= b; c -= rot(b,24); \
1091 * mono_method_get_imt_slot:
1093 * The IMT slot is embedded into AOTed code, so this must return the same value
1094 * for the same method across all executions. This means:
1095 * - pointers shouldn't be used as hash values.
1096 * - mono_metadata_str_hash () should be used for hashing strings.
1099 mono_method_get_imt_slot (MonoMethod *method)
1101 MONO_REQ_GC_NEUTRAL_MODE;
1103 MonoMethodSignature *sig;
1105 guint32 *hashes_start, *hashes;
1109 /* This can be used to stress tests the collision code */
1113 * We do this to simplify generic sharing. It will hurt
1114 * performance in cases where a class implements two different
1115 * instantiations of the same generic interface.
1116 * The code in build_imt_slots () depends on this.
1118 if (method->is_inflated)
1119 method = ((MonoMethodInflated*)method)->declaring;
1121 sig = mono_method_signature (method);
1122 hashes_count = sig->param_count + 4;
1123 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1124 hashes = hashes_start;
1126 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1127 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1128 method->klass->name_space, method->klass->name, method->name);
1131 /* Initialize hashes */
1132 hashes [0] = mono_metadata_str_hash (method->klass->name);
1133 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1134 hashes [2] = mono_metadata_str_hash (method->name);
1135 hashes [3] = mono_metadata_type_hash (sig->ret);
1136 for (i = 0; i < sig->param_count; i++) {
1137 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1140 /* Setup internal state */
1141 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1143 /* Handle most of the hashes */
1144 while (hashes_count > 3) {
1153 /* Handle the last 3 hashes (all the case statements fall through) */
1154 switch (hashes_count) {
1155 case 3 : c += hashes [2];
1156 case 2 : b += hashes [1];
1157 case 1 : a += hashes [0];
1159 case 0: /* nothing left to add */
1163 free (hashes_start);
1164 /* Report the result */
1165 return c % MONO_IMT_SIZE;
1174 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1175 MONO_REQ_GC_NEUTRAL_MODE;
1177 guint32 imt_slot = mono_method_get_imt_slot (method);
1178 MonoImtBuilderEntry *entry;
1180 if (slot_num >= 0 && imt_slot != slot_num) {
1181 /* we build just a single imt slot and this is not it */
1185 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1186 entry->key = method;
1187 entry->value.vtable_slot = vtable_slot;
1188 entry->next = imt_builder [imt_slot];
1189 if (imt_builder [imt_slot] != NULL) {
1190 entry->children = imt_builder [imt_slot]->children + 1;
1191 if (entry->children == 1) {
1192 mono_stats.imt_slots_with_collisions++;
1193 *imt_collisions_bitmap |= (1 << imt_slot);
1196 entry->children = 0;
1197 mono_stats.imt_used_slots++;
1199 imt_builder [imt_slot] = entry;
1202 char *method_name = mono_method_full_name (method, TRUE);
1203 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1204 method, method_name, imt_slot, vtable_slot, entry->children);
1205 g_free (method_name);
1212 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1214 MonoMethod *method = e->key;
1215 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1219 method->klass->name_space,
1220 method->klass->name,
1223 printf (" * %s: NULL\n", message);
1229 compare_imt_builder_entries (const void *p1, const void *p2) {
1230 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1231 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1233 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1237 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1239 MONO_REQ_GC_NEUTRAL_MODE;
1241 int count = end - start;
1242 int chunk_start = out_array->len;
1245 for (i = start; i < end; ++i) {
1246 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1247 item->key = sorted_array [i]->key;
1248 item->value = sorted_array [i]->value;
1249 item->has_target_code = sorted_array [i]->has_target_code;
1250 item->is_equals = TRUE;
1252 item->check_target_idx = out_array->len + 1;
1254 item->check_target_idx = 0;
1255 g_ptr_array_add (out_array, item);
1258 int middle = start + count / 2;
1259 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1261 item->key = sorted_array [middle]->key;
1262 item->is_equals = FALSE;
1263 g_ptr_array_add (out_array, item);
1264 imt_emit_ir (sorted_array, start, middle, out_array);
1265 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1271 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1272 MONO_REQ_GC_NEUTRAL_MODE;
1274 int number_of_entries = entries->children + 1;
1275 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1276 GPtrArray *result = g_ptr_array_new ();
1277 MonoImtBuilderEntry *current_entry;
1280 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1281 sorted_array [i] = current_entry;
1283 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1285 /*for (i = 0; i < number_of_entries; i++) {
1286 print_imt_entry (" sorted array:", sorted_array [i], i);
1289 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1291 free (sorted_array);
1296 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1298 MONO_REQ_GC_NEUTRAL_MODE;
1300 if (imt_builder_entry != NULL) {
1301 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1302 /* No collision, return the vtable slot contents */
1303 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1305 /* Collision, build the thunk */
1306 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1309 result = imt_thunk_builder (vtable, domain,
1310 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1311 for (i = 0; i < imt_ir->len; ++i)
1312 g_free (g_ptr_array_index (imt_ir, i));
1313 g_ptr_array_free (imt_ir, TRUE);
1325 static MonoImtBuilderEntry*
1326 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1329 * LOCKING: requires the loader and domain locks.
1333 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1335 MONO_REQ_GC_NEUTRAL_MODE;
1339 guint32 imt_collisions_bitmap = 0;
1340 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1341 int method_count = 0;
1342 gboolean record_method_count_for_max_collisions = FALSE;
1343 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1346 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1348 for (i = 0; i < klass->interface_offsets_count; ++i) {
1349 MonoClass *iface = klass->interfaces_packed [i];
1350 int interface_offset = klass->interface_offsets_packed [i];
1351 int method_slot_in_interface, vt_slot;
1353 if (mono_class_has_variant_generic_params (iface))
1354 has_variant_iface = TRUE;
1356 mono_class_setup_methods (iface);
1357 vt_slot = interface_offset;
1358 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1361 if (slot_num >= 0 && iface->is_inflated) {
1363 * The imt slot of the method is the same as for its declaring method,
1364 * see the comment in mono_method_get_imt_slot (), so we can
1365 * avoid inflating methods which will be discarded by
1366 * add_imt_builder_entry anyway.
1368 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1369 if (mono_method_get_imt_slot (method) != slot_num) {
1374 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1375 if (method->is_generic) {
1376 has_generic_virtual = TRUE;
1381 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1382 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1387 if (extra_interfaces) {
1388 int interface_offset = klass->vtable_size;
1390 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1391 MonoClass* iface = (MonoClass *)list_item->data;
1392 int method_slot_in_interface;
1393 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1394 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1396 if (method->is_generic)
1397 has_generic_virtual = TRUE;
1398 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1400 interface_offset += iface->method.count;
1403 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1404 /* overwrite the imt slot only if we're building all the entries or if
1405 * we're building this specific one
1407 if (slot_num < 0 || i == slot_num) {
1408 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1411 if (imt_builder [i]) {
1412 MonoImtBuilderEntry *entry;
1414 /* Link entries with imt_builder [i] */
1415 for (entry = entries; entry->next; entry = entry->next) {
1417 MonoMethod *method = (MonoMethod*)entry->key;
1418 char *method_name = mono_method_full_name (method, TRUE);
1419 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1420 g_free (method_name);
1423 entry->next = imt_builder [i];
1424 entries->children += imt_builder [i]->children + 1;
1426 imt_builder [i] = entries;
1429 if (has_generic_virtual || has_variant_iface) {
1431 * There might be collisions later when the the thunk is expanded.
1433 imt_collisions_bitmap |= (1 << i);
1436 * The IMT thunk might be called with an instance of one of the
1437 * generic virtual methods, so has to fallback to the IMT trampoline.
1439 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1441 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1444 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1448 if (imt_builder [i] != NULL) {
1449 int methods_in_slot = imt_builder [i]->children + 1;
1450 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1451 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1452 record_method_count_for_max_collisions = TRUE;
1454 method_count += methods_in_slot;
1458 mono_stats.imt_number_of_methods += method_count;
1459 if (record_method_count_for_max_collisions) {
1460 mono_stats.imt_method_count_when_max_collisions = method_count;
1463 for (i = 0; i < MONO_IMT_SIZE; i++) {
1464 MonoImtBuilderEntry* entry = imt_builder [i];
1465 while (entry != NULL) {
1466 MonoImtBuilderEntry* next = entry->next;
1472 /* we OR the bitmap since we may build just a single imt slot at a time */
1473 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1477 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1478 MONO_REQ_GC_NEUTRAL_MODE;
1480 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1484 * mono_vtable_build_imt_slot:
1485 * @vtable: virtual object table struct
1486 * @imt_slot: slot in the IMT table
1488 * Fill the given @imt_slot in the IMT table of @vtable with
1489 * a trampoline or a thunk for the case of collisions.
1490 * This is part of the internal mono API.
1492 * LOCKING: Take the domain lock.
1495 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1497 MONO_REQ_GC_NEUTRAL_MODE;
1499 gpointer *imt = (gpointer*)vtable;
1500 imt -= MONO_IMT_SIZE;
1501 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1503 /* no support for extra interfaces: the proxy objects will need
1504 * to build the complete IMT
1505 * Update and heck needs to ahppen inside the proper domain lock, as all
1506 * the changes made to a MonoVTable.
1508 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1509 mono_domain_lock (vtable->domain);
1510 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1511 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1512 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1513 mono_domain_unlock (vtable->domain);
1514 mono_loader_unlock ();
1519 * The first two free list entries both belong to the wait list: The
1520 * first entry is the pointer to the head of the list and the second
1521 * entry points to the last element. That way appending and removing
1522 * the first element are both O(1) operations.
1524 #ifdef MONO_SMALL_CONFIG
1525 #define NUM_FREE_LISTS 6
1527 #define NUM_FREE_LISTS 12
1529 #define FIRST_FREE_LIST_SIZE 64
1530 #define MAX_WAIT_LENGTH 50
1531 #define THUNK_THRESHOLD 10
1534 * LOCKING: The domain lock must be held.
1537 init_thunk_free_lists (MonoDomain *domain)
1539 MONO_REQ_GC_NEUTRAL_MODE;
1541 if (domain->thunk_free_lists)
1543 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1547 list_index_for_size (int item_size)
1550 int size = FIRST_FREE_LIST_SIZE;
1552 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1561 * mono_method_alloc_generic_virtual_thunk:
1563 * @size: size in bytes
1565 * Allocs size bytes to be used for the code of a generic virtual
1566 * thunk. It's either allocated from the domain's code manager or
1567 * reused from a previously invalidated piece.
1569 * LOCKING: The domain lock must be held.
1572 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1574 MONO_REQ_GC_NEUTRAL_MODE;
1576 static gboolean inited = FALSE;
1577 static int generic_virtual_thunks_size = 0;
1581 MonoThunkFreeList **l;
1583 init_thunk_free_lists (domain);
1585 size += sizeof (guint32);
1586 if (size < sizeof (MonoThunkFreeList))
1587 size = sizeof (MonoThunkFreeList);
1589 i = list_index_for_size (size);
1590 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1591 if ((*l)->size >= size) {
1592 MonoThunkFreeList *item = *l;
1594 return ((guint32*)item) + 1;
1598 /* no suitable item found - search lists of larger sizes */
1599 while (++i < NUM_FREE_LISTS) {
1600 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1603 g_assert (item->size > size);
1604 domain->thunk_free_lists [i] = item->next;
1605 return ((guint32*)item) + 1;
1608 /* still nothing found - allocate it */
1610 mono_counters_register ("Generic virtual thunk bytes",
1611 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1614 generic_virtual_thunks_size += size;
1616 p = (guint32 *)mono_domain_code_reserve (domain, size);
1619 mono_domain_lock (domain);
1620 if (!domain->generic_virtual_thunks)
1621 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1622 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1623 mono_domain_unlock (domain);
1629 * LOCKING: The domain lock must be held.
1632 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1634 MONO_REQ_GC_NEUTRAL_MODE;
1636 guint32 *p = (guint32 *)code;
1637 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1638 gboolean found = FALSE;
1640 mono_domain_lock (domain);
1641 if (!domain->generic_virtual_thunks)
1642 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1643 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1645 mono_domain_unlock (domain);
1648 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1650 init_thunk_free_lists (domain);
1652 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1653 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1654 int length = item->length;
1657 /* unlink the first item from the wait list */
1658 domain->thunk_free_lists [0] = item->next;
1659 domain->thunk_free_lists [0]->length = length - 1;
1661 i = list_index_for_size (item->size);
1663 /* put it in the free list */
1664 item->next = domain->thunk_free_lists [i];
1665 domain->thunk_free_lists [i] = item;
1669 if (domain->thunk_free_lists [1]) {
1670 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1671 domain->thunk_free_lists [0]->length++;
1673 g_assert (!domain->thunk_free_lists [0]);
1675 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1676 domain->thunk_free_lists [0]->length = 1;
1680 typedef struct _GenericVirtualCase {
1684 struct _GenericVirtualCase *next;
1685 } GenericVirtualCase;
1688 * get_generic_virtual_entries:
1690 * Return IMT entries for the generic virtual method instances and
1691 * variant interface methods for vtable slot
1694 static MonoImtBuilderEntry*
1695 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1697 MONO_REQ_GC_NEUTRAL_MODE;
1699 GenericVirtualCase *list;
1700 MonoImtBuilderEntry *entries;
1702 mono_domain_lock (domain);
1703 if (!domain->generic_virtual_cases)
1704 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1706 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1709 for (; list; list = list->next) {
1710 MonoImtBuilderEntry *entry;
1712 if (list->count < THUNK_THRESHOLD)
1715 entry = g_new0 (MonoImtBuilderEntry, 1);
1716 entry->key = list->method;
1717 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1718 entry->has_target_code = 1;
1720 entry->children = entries->children + 1;
1721 entry->next = entries;
1725 mono_domain_unlock (domain);
1727 /* FIXME: Leaking memory ? */
1732 * mono_method_add_generic_virtual_invocation:
1734 * @vtable_slot: pointer to the vtable slot
1735 * @method: the inflated generic virtual method
1736 * @code: the method's code
1738 * Registers a call via unmanaged code to a generic virtual method
1739 * instantiation or variant interface method. If the number of calls reaches a threshold
1740 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1741 * virtual method thunk.
1744 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1745 gpointer *vtable_slot,
1746 MonoMethod *method, gpointer code)
1748 MONO_REQ_GC_NEUTRAL_MODE;
1750 static gboolean inited = FALSE;
1751 static int num_added = 0;
1753 GenericVirtualCase *gvc, *list;
1754 MonoImtBuilderEntry *entries;
1758 mono_domain_lock (domain);
1759 if (!domain->generic_virtual_cases)
1760 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1762 /* Check whether the case was already added */
1763 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1766 if (gvc->method == method)
1771 /* If not found, make a new one */
1773 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1774 gvc->method = method;
1777 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1779 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1782 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1788 if (++gvc->count == THUNK_THRESHOLD) {
1789 gpointer *old_thunk = (void **)*vtable_slot;
1790 gpointer vtable_trampoline = NULL;
1791 gpointer imt_trampoline = NULL;
1793 if ((gpointer)vtable_slot < (gpointer)vtable) {
1794 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1795 int imt_slot = MONO_IMT_SIZE + displacement;
1797 /* Force the rebuild of the thunk at the next call */
1798 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1799 *vtable_slot = imt_trampoline;
1801 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1803 entries = get_generic_virtual_entries (domain, vtable_slot);
1805 sorted = imt_sort_slot_entries (entries);
1807 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1811 MonoImtBuilderEntry *next = entries->next;
1816 for (i = 0; i < sorted->len; ++i)
1817 g_free (g_ptr_array_index (sorted, i));
1818 g_ptr_array_free (sorted, TRUE);
1821 #ifndef __native_client__
1822 /* We don't re-use any thunks as there is a lot of overhead */
1823 /* to deleting and re-using code in Native Client. */
1824 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1825 invalidate_generic_virtual_thunk (domain, old_thunk);
1829 mono_domain_unlock (domain);
1832 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1835 * mono_class_vtable:
1836 * @domain: the application domain
1837 * @class: the class to initialize
1839 * VTables are domain specific because we create domain specific code, and
1840 * they contain the domain specific static class data.
1841 * On failure, NULL is returned, and class->exception_type is set.
1844 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1846 return mono_class_vtable_full (domain, klass, FALSE);
1850 * mono_class_vtable_full:
1851 * @domain: the application domain
1852 * @class: the class to initialize
1853 * @raise_on_error if an exception should be raised on failure or not
1855 * VTables are domain specific because we create domain specific code, and
1856 * they contain the domain specific static class data.
1859 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1861 MONO_REQ_GC_UNSAFE_MODE;
1863 MonoClassRuntimeInfo *runtime_info;
1867 if (klass->exception_type) {
1869 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1873 /* this check can be inlined in jitted code, too */
1874 runtime_info = klass->runtime_info;
1875 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1876 return runtime_info->domain_vtables [domain->domain_id];
1877 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1881 * mono_class_try_get_vtable:
1882 * @domain: the application domain
1883 * @class: the class to initialize
1885 * This function tries to get the associated vtable from @class if
1886 * it was already created.
1889 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1891 MONO_REQ_GC_NEUTRAL_MODE;
1893 MonoClassRuntimeInfo *runtime_info;
1897 runtime_info = klass->runtime_info;
1898 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1899 return runtime_info->domain_vtables [domain->domain_id];
1904 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1906 MONO_REQ_GC_NEUTRAL_MODE;
1908 size_t alloc_offset;
1911 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1912 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1913 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1915 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1916 g_assert ((imt_table_bytes & 7) == 4);
1923 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1927 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1929 MONO_REQ_GC_UNSAFE_MODE;
1932 MonoClassRuntimeInfo *runtime_info, *old_info;
1933 MonoClassField *field;
1935 int i, vtable_slots;
1936 size_t imt_table_bytes;
1938 guint32 vtable_size, class_size;
1940 gpointer *interface_offsets;
1942 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1943 mono_domain_lock (domain);
1944 runtime_info = klass->runtime_info;
1945 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1946 mono_domain_unlock (domain);
1947 mono_loader_unlock ();
1948 return runtime_info->domain_vtables [domain->domain_id];
1950 if (!klass->inited || klass->exception_type) {
1951 if (!mono_class_init (klass) || klass->exception_type) {
1952 mono_domain_unlock (domain);
1953 mono_loader_unlock ();
1955 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1960 /* Array types require that their element type be valid*/
1961 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1962 MonoClass *element_class = klass->element_class;
1963 if (!element_class->inited)
1964 mono_class_init (element_class);
1966 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1967 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1968 mono_class_setup_vtable (element_class);
1970 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1971 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1972 if (klass->exception_type == MONO_EXCEPTION_NONE)
1973 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1974 mono_domain_unlock (domain);
1975 mono_loader_unlock ();
1977 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1983 * For some classes, mono_class_init () already computed klass->vtable_size, and
1984 * that is all that is needed because of the vtable trampolines.
1986 if (!klass->vtable_size)
1987 mono_class_setup_vtable (klass);
1989 if (klass->generic_class && !klass->vtable)
1990 mono_class_check_vtable_constraints (klass, NULL);
1992 /* Initialize klass->has_finalize */
1993 mono_class_has_finalizer (klass);
1995 if (klass->exception_type) {
1996 mono_domain_unlock (domain);
1997 mono_loader_unlock ();
1999 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2003 vtable_slots = klass->vtable_size;
2004 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2005 class_size = mono_class_data_size (klass);
2009 if (klass->interface_offsets_count) {
2010 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2011 mono_stats.imt_number_of_tables++;
2012 mono_stats.imt_tables_size += imt_table_bytes;
2014 imt_table_bytes = 0;
2017 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2019 mono_stats.used_class_count++;
2020 mono_stats.class_vtable_size += vtable_size;
2022 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2023 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2024 g_assert (!((gsize)vt & 7));
2027 vt->rank = klass->rank;
2028 vt->domain = domain;
2030 mono_class_compute_gc_descriptor (klass);
2032 * We can't use typed allocation in the non-root domains, since the
2033 * collector needs the GC descriptor stored in the vtable even after
2034 * the mempool containing the vtable is destroyed when the domain is
2035 * unloaded. An alternative might be to allocate vtables in the GC
2036 * heap, but this does not seem to work (it leads to crashes inside
2037 * libgc). If that approach is tried, two gc descriptors need to be
2038 * allocated for each class: one for the root domain, and one for all
2039 * other domains. The second descriptor should contain a bit for the
2040 * vtable field in MonoObject, since we can no longer assume the
2041 * vtable is reachable by other roots after the appdomain is unloaded.
2043 #ifdef HAVE_BOEHM_GC
2044 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2045 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2048 vt->gc_descr = klass->gc_descr;
2050 gc_bits = mono_gc_get_vtable_bits (klass);
2051 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2053 vt->gc_bits = gc_bits;
2056 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2057 if (klass->has_static_refs) {
2058 MonoGCDescriptor statics_gc_descr;
2060 gsize default_bitmap [4] = {0};
2063 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2064 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2065 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2066 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2067 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2068 if (bitmap != default_bitmap)
2071 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2073 vt->has_static_fields = TRUE;
2074 mono_stats.class_static_data_size += class_size;
2078 while ((field = mono_class_get_fields (klass, &iter))) {
2079 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2081 if (mono_field_is_deleted (field))
2083 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2084 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2085 if (special_static != SPECIAL_STATIC_NONE) {
2086 guint32 size, offset;
2088 gsize default_bitmap [4] = {0};
2093 if (mono_type_is_reference (field->type)) {
2094 default_bitmap [0] = 1;
2096 bitmap = default_bitmap;
2097 } else if (mono_type_is_struct (field->type)) {
2098 fclass = mono_class_from_mono_type (field->type);
2099 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2100 numbits = max_set + 1;
2102 default_bitmap [0] = 0;
2104 bitmap = default_bitmap;
2106 size = mono_type_size (field->type, &align);
2107 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2108 if (!domain->special_static_fields)
2109 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2110 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2111 if (bitmap != default_bitmap)
2114 * This marks the field as special static to speed up the
2115 * checks in mono_field_static_get/set_value ().
2121 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2122 MonoClass *fklass = mono_class_from_mono_type (field->type);
2123 const char *data = mono_field_get_data (field);
2125 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2126 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2127 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2130 if (fklass->valuetype) {
2131 memcpy (t, data, mono_class_value_size (fklass, NULL));
2133 /* it's a pointer type: add check */
2134 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2141 vt->max_interface_id = klass->max_interface_id;
2142 vt->interface_bitmap = klass->interface_bitmap;
2144 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2145 // class->name, klass->interface_offsets_count);
2147 /* Initialize vtable */
2148 if (callbacks.get_vtable_trampoline) {
2149 // This also covers the AOT case
2150 for (i = 0; i < klass->vtable_size; ++i) {
2151 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2154 mono_class_setup_vtable (klass);
2156 for (i = 0; i < klass->vtable_size; ++i) {
2159 if ((cm = klass->vtable [i]))
2160 vt->vtable [i] = arch_create_jit_trampoline (cm);
2164 if (imt_table_bytes) {
2165 /* Now that the vtable is full, we can actually fill up the IMT */
2166 for (i = 0; i < MONO_IMT_SIZE; ++i)
2167 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2171 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2172 * re-acquire them and check if another thread has created the vtable in the meantime.
2174 /* Special case System.MonoType to avoid infinite recursion */
2175 if (klass != mono_defaults.monotype_class) {
2176 /*FIXME check for OOM*/
2177 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2178 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2179 /* This is unregistered in
2180 unregister_vtable_reflection_type() in
2182 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2185 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2187 /* class_vtable_array keeps an array of created vtables
2189 g_ptr_array_add (domain->class_vtable_array, vt);
2190 /* klass->runtime_info is protected by the loader lock, both when
2191 * it it enlarged and when it is stored info.
2195 * Store the vtable in klass->runtime_info.
2196 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2198 mono_memory_barrier ();
2200 old_info = klass->runtime_info;
2201 if (old_info && old_info->max_domain >= domain->domain_id) {
2202 /* someone already created a large enough runtime info */
2203 old_info->domain_vtables [domain->domain_id] = vt;
2205 int new_size = domain->domain_id;
2207 new_size = MAX (new_size, old_info->max_domain);
2209 /* make the new size a power of two */
2211 while (new_size > i)
2214 /* this is a bounded memory retention issue: may want to
2215 * handle it differently when we'll have a rcu-like system.
2217 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2218 runtime_info->max_domain = new_size - 1;
2219 /* copy the stuff from the older info */
2221 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2223 runtime_info->domain_vtables [domain->domain_id] = vt;
2225 mono_memory_barrier ();
2226 klass->runtime_info = runtime_info;
2229 if (klass == mono_defaults.monotype_class) {
2230 /*FIXME check for OOM*/
2231 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2232 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2233 /* This is unregistered in
2234 unregister_vtable_reflection_type() in
2236 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2239 mono_domain_unlock (domain);
2240 mono_loader_unlock ();
2242 /* make sure the parent is initialized */
2243 /*FIXME shouldn't this fail the current type?*/
2245 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2250 #ifndef DISABLE_REMOTING
2252 * mono_class_proxy_vtable:
2253 * @domain: the application domain
2254 * @remove_class: the remote class
2256 * Creates a vtable for transparent proxies. It is basically
2257 * a copy of the real vtable of the class wrapped in @remote_class,
2258 * but all function pointers invoke the remoting functions, and
2259 * vtable->klass points to the transparent proxy class, and not to @class.
2262 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2264 MONO_REQ_GC_UNSAFE_MODE;
2267 MonoVTable *vt, *pvt;
2268 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2270 GSList *extra_interfaces = NULL;
2271 MonoClass *klass = remote_class->proxy_class;
2272 gpointer *interface_offsets;
2275 size_t imt_table_bytes;
2277 #ifdef COMPRESSED_INTERFACE_BITMAP
2281 vt = mono_class_vtable (domain, klass);
2282 g_assert (vt); /*FIXME property handle failure*/
2283 max_interface_id = vt->max_interface_id;
2285 /* Calculate vtable space for extra interfaces */
2286 for (j = 0; j < remote_class->interface_count; j++) {
2287 MonoClass* iclass = remote_class->interfaces[j];
2291 /*FIXME test for interfaces with variant generic arguments*/
2292 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2293 continue; /* interface implemented by the class */
2294 if (g_slist_find (extra_interfaces, iclass))
2297 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2299 method_count = mono_class_num_methods (iclass);
2301 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2302 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2304 for (i = 0; i < ifaces->len; ++i) {
2305 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2306 /*FIXME test for interfaces with variant generic arguments*/
2307 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2308 continue; /* interface implemented by the class */
2309 if (g_slist_find (extra_interfaces, ic))
2311 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2312 method_count += mono_class_num_methods (ic);
2314 g_ptr_array_free (ifaces, TRUE);
2317 extra_interface_vtsize += method_count * sizeof (gpointer);
2318 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2321 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2322 mono_stats.imt_number_of_tables++;
2323 mono_stats.imt_tables_size += imt_table_bytes;
2325 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2327 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2329 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2330 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2331 g_assert (!((gsize)pvt & 7));
2333 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2335 pvt->klass = mono_defaults.transparent_proxy_class;
2336 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2337 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2339 /* initialize vtable */
2340 mono_class_setup_vtable (klass);
2341 for (i = 0; i < klass->vtable_size; ++i) {
2344 if ((cm = klass->vtable [i]))
2345 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2347 pvt->vtable [i] = NULL;
2350 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2351 /* create trampolines for abstract methods */
2352 for (k = klass; k; k = k->parent) {
2354 gpointer iter = NULL;
2355 while ((m = mono_class_get_methods (k, &iter)))
2356 if (!pvt->vtable [m->slot])
2357 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2361 pvt->max_interface_id = max_interface_id;
2362 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2363 #ifdef COMPRESSED_INTERFACE_BITMAP
2364 bitmap = (uint8_t *)g_malloc0 (bsize);
2366 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2369 for (i = 0; i < klass->interface_offsets_count; ++i) {
2370 int interface_id = klass->interfaces_packed [i]->interface_id;
2371 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2374 if (extra_interfaces) {
2375 int slot = klass->vtable_size;
2381 /* Create trampolines for the methods of the interfaces */
2382 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2383 interf = (MonoClass *)list_item->data;
2385 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2389 while ((cm = mono_class_get_methods (interf, &iter)))
2390 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2392 slot += mono_class_num_methods (interf);
2396 /* Now that the vtable is full, we can actually fill up the IMT */
2397 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2398 if (extra_interfaces) {
2399 g_slist_free (extra_interfaces);
2402 #ifdef COMPRESSED_INTERFACE_BITMAP
2403 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2404 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2405 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2408 pvt->interface_bitmap = bitmap;
2413 #endif /* DISABLE_REMOTING */
2416 * mono_class_field_is_special_static:
2418 * Returns whether @field is a thread/context static field.
2421 mono_class_field_is_special_static (MonoClassField *field)
2423 MONO_REQ_GC_NEUTRAL_MODE
2425 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2427 if (mono_field_is_deleted (field))
2429 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2430 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2437 * mono_class_field_get_special_static_type:
2438 * @field: The MonoClassField describing the field.
2440 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2441 * SPECIAL_STATIC_NONE otherwise.
2444 mono_class_field_get_special_static_type (MonoClassField *field)
2446 MONO_REQ_GC_NEUTRAL_MODE
2448 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2449 return SPECIAL_STATIC_NONE;
2450 if (mono_field_is_deleted (field))
2451 return SPECIAL_STATIC_NONE;
2452 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2453 return field_is_special_static (field->parent, field);
2454 return SPECIAL_STATIC_NONE;
2458 * mono_class_has_special_static_fields:
2460 * Returns whenever @klass has any thread/context static fields.
2463 mono_class_has_special_static_fields (MonoClass *klass)
2465 MONO_REQ_GC_NEUTRAL_MODE
2467 MonoClassField *field;
2471 while ((field = mono_class_get_fields (klass, &iter))) {
2472 g_assert (field->parent == klass);
2473 if (mono_class_field_is_special_static (field))
2480 #ifndef DISABLE_REMOTING
2482 * create_remote_class_key:
2483 * Creates an array of pointers that can be used as a hash key for a remote class.
2484 * The first element of the array is the number of pointers.
2487 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2489 MONO_REQ_GC_NEUTRAL_MODE;
2494 if (remote_class == NULL) {
2495 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2496 key = (void **)g_malloc (sizeof(gpointer) * 3);
2497 key [0] = GINT_TO_POINTER (2);
2498 key [1] = mono_defaults.marshalbyrefobject_class;
2499 key [2] = extra_class;
2501 key = (void **)g_malloc (sizeof(gpointer) * 2);
2502 key [0] = GINT_TO_POINTER (1);
2503 key [1] = extra_class;
2506 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2507 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2508 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2509 key [1] = remote_class->proxy_class;
2511 // Keep the list of interfaces sorted
2512 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2513 if (extra_class && remote_class->interfaces [i] > extra_class) {
2514 key [j++] = extra_class;
2517 key [j] = remote_class->interfaces [i];
2520 key [j] = extra_class;
2522 // Replace the old class. The interface list is the same
2523 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2524 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2525 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2526 for (i = 0; i < remote_class->interface_count; i++)
2527 key [2 + i] = remote_class->interfaces [i];
2535 * copy_remote_class_key:
2537 * Make a copy of KEY in the domain and return the copy.
2540 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2542 MONO_REQ_GC_NEUTRAL_MODE
2544 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2545 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2547 memcpy (mp_key, key, key_size);
2553 * mono_remote_class:
2554 * @domain: the application domain
2555 * @class_name: name of the remote class
2557 * Creates and initializes a MonoRemoteClass object for a remote type.
2559 * Can raise an exception on failure.
2562 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2564 MONO_REQ_GC_UNSAFE_MODE;
2567 MonoRemoteClass *rc;
2568 gpointer* key, *mp_key;
2571 key = create_remote_class_key (NULL, proxy_class);
2573 mono_domain_lock (domain);
2574 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2578 mono_domain_unlock (domain);
2582 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2583 if (!mono_error_ok (&error)) {
2585 mono_domain_unlock (domain);
2586 mono_error_raise_exception (&error);
2589 mp_key = copy_remote_class_key (domain, key);
2593 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2594 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2595 rc->interface_count = 1;
2596 rc->interfaces [0] = proxy_class;
2597 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2599 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2600 rc->interface_count = 0;
2601 rc->proxy_class = proxy_class;
2604 rc->default_vtable = NULL;
2605 rc->xdomain_vtable = NULL;
2606 rc->proxy_class_name = name;
2607 #ifndef DISABLE_PERFCOUNTERS
2608 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2611 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2613 mono_domain_unlock (domain);
2618 * clone_remote_class:
2619 * Creates a copy of the remote_class, adding the provided class or interface
2621 static MonoRemoteClass*
2622 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2624 MONO_REQ_GC_NEUTRAL_MODE;
2626 MonoRemoteClass *rc;
2627 gpointer* key, *mp_key;
2629 key = create_remote_class_key (remote_class, extra_class);
2630 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2636 mp_key = copy_remote_class_key (domain, key);
2640 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2642 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2643 rc->proxy_class = remote_class->proxy_class;
2644 rc->interface_count = remote_class->interface_count + 1;
2646 // Keep the list of interfaces sorted, since the hash key of
2647 // the remote class depends on this
2648 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2649 if (remote_class->interfaces [i] > extra_class && i == j)
2650 rc->interfaces [j++] = extra_class;
2651 rc->interfaces [j] = remote_class->interfaces [i];
2654 rc->interfaces [j] = extra_class;
2656 // Replace the old class. The interface array is the same
2657 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2658 rc->proxy_class = extra_class;
2659 rc->interface_count = remote_class->interface_count;
2660 if (rc->interface_count > 0)
2661 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2664 rc->default_vtable = NULL;
2665 rc->xdomain_vtable = NULL;
2666 rc->proxy_class_name = remote_class->proxy_class_name;
2668 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2674 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2676 MONO_REQ_GC_UNSAFE_MODE;
2678 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2679 mono_domain_lock (domain);
2680 if (rp->target_domain_id != -1) {
2681 if (remote_class->xdomain_vtable == NULL)
2682 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2683 mono_domain_unlock (domain);
2684 mono_loader_unlock ();
2685 return remote_class->xdomain_vtable;
2687 if (remote_class->default_vtable == NULL) {
2690 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2691 klass = mono_class_from_mono_type (type);
2693 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)))
2694 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2697 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2700 mono_domain_unlock (domain);
2701 mono_loader_unlock ();
2702 return remote_class->default_vtable;
2706 * mono_upgrade_remote_class:
2707 * @domain: the application domain
2708 * @tproxy: the proxy whose remote class has to be upgraded.
2709 * @klass: class to which the remote class can be casted.
2711 * Updates the vtable of the remote class by adding the necessary method slots
2712 * and interface offsets so it can be safely casted to klass. klass can be a
2713 * class or an interface.
2716 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2718 MONO_REQ_GC_UNSAFE_MODE;
2720 MonoTransparentProxy *tproxy;
2721 MonoRemoteClass *remote_class;
2722 gboolean redo_vtable;
2724 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2725 mono_domain_lock (domain);
2727 tproxy = (MonoTransparentProxy*) proxy_object;
2728 remote_class = tproxy->remote_class;
2730 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2733 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2734 if (remote_class->interfaces [i] == klass)
2735 redo_vtable = FALSE;
2738 redo_vtable = (remote_class->proxy_class != klass);
2742 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2743 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2746 mono_domain_unlock (domain);
2747 mono_loader_unlock ();
2749 #endif /* DISABLE_REMOTING */
2753 * mono_object_get_virtual_method:
2754 * @obj: object to operate on.
2757 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2758 * the instance of a callvirt of method.
2761 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2763 MONO_REQ_GC_UNSAFE_MODE;
2766 MonoMethod **vtable;
2767 gboolean is_proxy = FALSE;
2768 MonoMethod *res = NULL;
2770 klass = mono_object_class (obj);
2771 #ifndef DISABLE_REMOTING
2772 if (klass == mono_defaults.transparent_proxy_class) {
2773 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2778 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2781 mono_class_setup_vtable (klass);
2782 vtable = klass->vtable;
2784 if (method->slot == -1) {
2785 /* method->slot might not be set for instances of generic methods */
2786 if (method->is_inflated) {
2787 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2788 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2791 g_assert_not_reached ();
2795 /* check method->slot is a valid index: perform isinstance? */
2796 if (method->slot != -1) {
2797 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2799 gboolean variance_used = FALSE;
2800 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2801 g_assert (iface_offset > 0);
2802 res = vtable [iface_offset + method->slot];
2805 res = vtable [method->slot];
2809 #ifndef DISABLE_REMOTING
2811 /* It may be an interface, abstract class method or generic method */
2812 if (!res || mono_method_signature (res)->generic_param_count)
2815 /* generic methods demand invoke_with_check */
2816 if (mono_method_signature (res)->generic_param_count)
2817 res = mono_marshal_get_remoting_invoke_with_check (res);
2820 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2821 res = mono_cominterop_get_invoke (res);
2824 res = mono_marshal_get_remoting_invoke (res);
2829 if (method->is_inflated) {
2831 /* Have to inflate the result */
2832 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2833 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2843 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2845 g_error ("runtime invoke called on uninitialized runtime");
2849 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2852 * mono_runtime_invoke:
2853 * @method: method to invoke
2854 * @obJ: object instance
2855 * @params: arguments to the method
2856 * @exc: exception information.
2858 * Invokes the method represented by @method on the object @obj.
2860 * obj is the 'this' pointer, it should be NULL for static
2861 * methods, a MonoObject* for object instances and a pointer to
2862 * the value type for value types.
2864 * The params array contains the arguments to the method with the
2865 * same convention: MonoObject* pointers for object instances and
2866 * pointers to the value type otherwise.
2868 * From unmanaged code you'll usually use the
2869 * mono_runtime_invoke() variant.
2871 * Note that this function doesn't handle virtual methods for
2872 * you, it will exec the exact method you pass: we still need to
2873 * expose a function to lookup the derived class implementation
2874 * of a virtual method (there are examples of this in the code,
2877 * You can pass NULL as the exc argument if you don't want to
2878 * catch exceptions, otherwise, *exc will be set to the exception
2879 * thrown, if any. if an exception is thrown, you can't use the
2880 * MonoObject* result from the function.
2882 * If the method returns a value type, it is boxed in an object
2886 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2888 MONO_REQ_GC_UNSAFE_MODE;
2892 if (mono_runtime_get_no_exec ())
2893 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2895 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2896 mono_profiler_method_start_invoke (method);
2898 result = default_mono_runtime_invoke (method, obj, params, exc);
2900 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2901 mono_profiler_method_end_invoke (method);
2907 * mono_method_get_unmanaged_thunk:
2908 * @method: method to generate a thunk for.
2910 * Returns an unmanaged->managed thunk that can be used to call
2911 * a managed method directly from C.
2913 * The thunk's C signature closely matches the managed signature:
2915 * C#: public bool Equals (object obj);
2916 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2917 * MonoObject*, MonoException**);
2919 * The 1st ("this") parameter must not be used with static methods:
2921 * C#: public static bool ReferenceEquals (object a, object b);
2922 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2925 * The last argument must be a non-null pointer of a MonoException* pointer.
2926 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2927 * exception has been thrown in managed code. Otherwise it will point
2928 * to the MonoException* caught by the thunk. In this case, the result of
2929 * the thunk is undefined:
2931 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2932 * MonoException *ex = NULL;
2933 * Equals func = mono_method_get_unmanaged_thunk (method);
2934 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2936 * // handle exception
2939 * The calling convention of the thunk matches the platform's default
2940 * convention. This means that under Windows, C declarations must
2941 * contain the __stdcall attribute:
2943 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2944 * MonoObject*, MonoException**);
2948 * Value type arguments and return values are treated as they were objects:
2950 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2951 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2953 * Arguments must be properly boxed upon trunk's invocation, while return
2954 * values must be unboxed.
2957 mono_method_get_unmanaged_thunk (MonoMethod *method)
2959 MONO_REQ_GC_NEUTRAL_MODE;
2960 MONO_REQ_API_ENTRYPOINT;
2964 MONO_PREPARE_RESET_BLOCKING;
2965 method = mono_marshal_get_thunk_invoke_wrapper (method);
2966 res = mono_compile_method (method);
2967 MONO_FINISH_RESET_BLOCKING;
2973 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2975 MONO_REQ_GC_UNSAFE_MODE;
2979 /* object fields cannot be byref, so we don't need a
2981 gpointer *p = (gpointer*)dest;
2988 case MONO_TYPE_BOOLEAN:
2990 case MONO_TYPE_U1: {
2991 guint8 *p = (guint8*)dest;
2992 *p = value ? *(guint8*)value : 0;
2997 case MONO_TYPE_CHAR: {
2998 guint16 *p = (guint16*)dest;
2999 *p = value ? *(guint16*)value : 0;
3002 #if SIZEOF_VOID_P == 4
3007 case MONO_TYPE_U4: {
3008 gint32 *p = (gint32*)dest;
3009 *p = value ? *(gint32*)value : 0;
3012 #if SIZEOF_VOID_P == 8
3017 case MONO_TYPE_U8: {
3018 gint64 *p = (gint64*)dest;
3019 *p = value ? *(gint64*)value : 0;
3022 case MONO_TYPE_R4: {
3023 float *p = (float*)dest;
3024 *p = value ? *(float*)value : 0;
3027 case MONO_TYPE_R8: {
3028 double *p = (double*)dest;
3029 *p = value ? *(double*)value : 0;
3032 case MONO_TYPE_STRING:
3033 case MONO_TYPE_SZARRAY:
3034 case MONO_TYPE_CLASS:
3035 case MONO_TYPE_OBJECT:
3036 case MONO_TYPE_ARRAY:
3037 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3039 case MONO_TYPE_FNPTR:
3040 case MONO_TYPE_PTR: {
3041 gpointer *p = (gpointer*)dest;
3042 *p = deref_pointer? *(gpointer*)value: value;
3045 case MONO_TYPE_VALUETYPE:
3046 /* note that 't' and 'type->type' can be different */
3047 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3048 t = mono_class_enum_basetype (type->data.klass)->type;
3051 MonoClass *klass = mono_class_from_mono_type (type);
3052 int size = mono_class_value_size (klass, NULL);
3054 mono_gc_bzero_atomic (dest, size);
3056 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3059 case MONO_TYPE_GENERICINST:
3060 t = type->data.generic_class->container_class->byval_arg.type;
3063 g_error ("got type %x", type->type);
3068 * mono_field_set_value:
3069 * @obj: Instance object
3070 * @field: MonoClassField describing the field to set
3071 * @value: The value to be set
3073 * Sets the value of the field described by @field in the object instance @obj
3074 * to the value passed in @value. This method should only be used for instance
3075 * fields. For static fields, use mono_field_static_set_value.
3077 * The value must be on the native format of the field type.
3080 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3082 MONO_REQ_GC_UNSAFE_MODE;
3086 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3088 dest = (char*)obj + field->offset;
3089 mono_copy_value (field->type, dest, value, FALSE);
3093 * mono_field_static_set_value:
3094 * @field: MonoClassField describing the field to set
3095 * @value: The value to be set
3097 * Sets the value of the static field described by @field
3098 * to the value passed in @value.
3100 * The value must be on the native format of the field type.
3103 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3105 MONO_REQ_GC_UNSAFE_MODE;
3109 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3110 /* you cant set a constant! */
3111 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3113 if (field->offset == -1) {
3114 /* Special static */
3117 mono_domain_lock (vt->domain);
3118 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3119 mono_domain_unlock (vt->domain);
3120 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3122 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3124 mono_copy_value (field->type, dest, value, FALSE);
3128 * mono_vtable_get_static_field_data:
3130 * Internal use function: return a pointer to the memory holding the static fields
3131 * for a class or NULL if there are no static fields.
3132 * This is exported only for use by the debugger.
3135 mono_vtable_get_static_field_data (MonoVTable *vt)
3137 MONO_REQ_GC_NEUTRAL_MODE
3139 if (!vt->has_static_fields)
3141 return vt->vtable [vt->klass->vtable_size];
3145 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3147 MONO_REQ_GC_UNSAFE_MODE;
3151 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3152 if (field->offset == -1) {
3153 /* Special static */
3156 mono_domain_lock (vt->domain);
3157 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3158 mono_domain_unlock (vt->domain);
3159 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3161 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3164 src = (guint8*)obj + field->offset;
3171 * mono_field_get_value:
3172 * @obj: Object instance
3173 * @field: MonoClassField describing the field to fetch information from
3174 * @value: pointer to the location where the value will be stored
3176 * Use this routine to get the value of the field @field in the object
3179 * The pointer provided by value must be of the field type, for reference
3180 * types this is a MonoObject*, for value types its the actual pointer to
3185 * mono_field_get_value (obj, int_field, &i);
3188 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3190 MONO_REQ_GC_UNSAFE_MODE;
3196 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3198 src = (char*)obj + field->offset;
3199 mono_copy_value (field->type, value, src, TRUE);
3203 * mono_field_get_value_object:
3204 * @domain: domain where the object will be created (if boxing)
3205 * @field: MonoClassField describing the field to fetch information from
3206 * @obj: The object instance for the field.
3208 * Returns: a new MonoObject with the value from the given field. If the
3209 * field represents a value type, the value is boxed.
3213 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3215 MONO_REQ_GC_UNSAFE_MODE;
3219 MonoVTable *vtable = NULL;
3221 gboolean is_static = FALSE;
3222 gboolean is_ref = FALSE;
3223 gboolean is_literal = FALSE;
3224 gboolean is_ptr = FALSE;
3226 MonoType *type = mono_field_get_type_checked (field, &error);
3228 if (!mono_error_ok (&error))
3229 mono_error_raise_exception (&error);
3231 switch (type->type) {
3232 case MONO_TYPE_STRING:
3233 case MONO_TYPE_OBJECT:
3234 case MONO_TYPE_CLASS:
3235 case MONO_TYPE_ARRAY:
3236 case MONO_TYPE_SZARRAY:
3241 case MONO_TYPE_BOOLEAN:
3244 case MONO_TYPE_CHAR:
3253 case MONO_TYPE_VALUETYPE:
3254 is_ref = type->byref;
3256 case MONO_TYPE_GENERICINST:
3257 is_ref = !mono_type_generic_inst_is_valuetype (type);
3263 g_error ("type 0x%x not handled in "
3264 "mono_field_get_value_object", type->type);
3268 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3271 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3275 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3276 if (!vtable->initialized)
3277 mono_runtime_class_init (vtable);
3285 get_default_field_value (domain, field, &o);
3286 } else if (is_static) {
3287 mono_field_static_get_value (vtable, field, &o);
3289 mono_field_get_value (obj, field, &o);
3295 static MonoMethod *m;
3301 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3302 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3308 get_default_field_value (domain, field, v);
3309 } else if (is_static) {
3310 mono_field_static_get_value (vtable, field, v);
3312 mono_field_get_value (obj, field, v);
3315 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3316 args [0] = ptr ? *ptr : NULL;
3317 args [1] = mono_type_get_object (mono_domain_get (), type);
3319 return mono_runtime_invoke (m, NULL, args, NULL);
3322 /* boxed value type */
3323 klass = mono_class_from_mono_type (type);
3325 if (mono_class_is_nullable (klass))
3326 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3328 o = mono_object_new (domain, klass);
3329 v = ((gchar *) o) + sizeof (MonoObject);
3332 get_default_field_value (domain, field, v);
3333 } else if (is_static) {
3334 mono_field_static_get_value (vtable, field, v);
3336 mono_field_get_value (obj, field, v);
3343 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3345 MONO_REQ_GC_UNSAFE_MODE;
3348 const char *p = blob;
3349 mono_metadata_decode_blob_size (p, &p);
3352 case MONO_TYPE_BOOLEAN:
3355 *(guint8 *) value = *p;
3357 case MONO_TYPE_CHAR:
3360 *(guint16*) value = read16 (p);
3364 *(guint32*) value = read32 (p);
3368 *(guint64*) value = read64 (p);
3371 readr4 (p, (float*) value);
3374 readr8 (p, (double*) value);
3376 case MONO_TYPE_STRING:
3377 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3379 case MONO_TYPE_CLASS:
3380 *(gpointer*) value = NULL;
3384 g_warning ("type 0x%02x should not be in constant table", type);
3390 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3392 MONO_REQ_GC_NEUTRAL_MODE;
3394 MonoTypeEnum def_type;
3397 data = mono_class_get_field_default_value (field, &def_type);
3398 mono_get_constant_value_from_blob (domain, def_type, data, value);
3402 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3404 MONO_REQ_GC_UNSAFE_MODE;
3408 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3410 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3411 get_default_field_value (vt->domain, field, value);
3415 if (field->offset == -1) {
3416 /* Special static */
3417 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3418 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3420 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3422 mono_copy_value (field->type, value, src, TRUE);
3426 * mono_field_static_get_value:
3427 * @vt: vtable to the object
3428 * @field: MonoClassField describing the field to fetch information from
3429 * @value: where the value is returned
3431 * Use this routine to get the value of the static field @field value.
3433 * The pointer provided by value must be of the field type, for reference
3434 * types this is a MonoObject*, for value types its the actual pointer to
3439 * mono_field_static_get_value (vt, int_field, &i);
3442 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3444 MONO_REQ_GC_NEUTRAL_MODE;
3446 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3450 * mono_property_set_value:
3451 * @prop: MonoProperty to set
3452 * @obj: instance object on which to act
3453 * @params: parameters to pass to the propery
3454 * @exc: optional exception
3456 * Invokes the property's set method with the given arguments on the
3457 * object instance obj (or NULL for static properties).
3459 * You can pass NULL as the exc argument if you don't want to
3460 * catch exceptions, otherwise, *exc will be set to the exception
3461 * thrown, if any. if an exception is thrown, you can't use the
3462 * MonoObject* result from the function.
3465 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3467 MONO_REQ_GC_UNSAFE_MODE;
3469 default_mono_runtime_invoke (prop->set, obj, params, exc);
3473 * mono_property_get_value:
3474 * @prop: MonoProperty to fetch
3475 * @obj: instance object on which to act
3476 * @params: parameters to pass to the propery
3477 * @exc: optional exception
3479 * Invokes the property's get method with the given arguments on the
3480 * object instance obj (or NULL for static properties).
3482 * You can pass NULL as the exc argument if you don't want to
3483 * catch exceptions, otherwise, *exc will be set to the exception
3484 * thrown, if any. if an exception is thrown, you can't use the
3485 * MonoObject* result from the function.
3487 * Returns: the value from invoking the get method on the property.
3490 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3492 MONO_REQ_GC_UNSAFE_MODE;
3494 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3498 * mono_nullable_init:
3499 * @buf: The nullable structure to initialize.
3500 * @value: the value to initialize from
3501 * @klass: the type for the object
3503 * Initialize the nullable structure pointed to by @buf from @value which
3504 * should be a boxed value type. The size of @buf should be able to hold
3505 * as much data as the @klass->instance_size (which is the number of bytes
3506 * that will be copies).
3508 * Since Nullables have variable structure, we can not define a C
3509 * structure for them.
3512 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3514 MONO_REQ_GC_UNSAFE_MODE;
3516 MonoClass *param_class = klass->cast_class;
3518 mono_class_setup_fields_locking (klass);
3519 g_assert (klass->fields_inited);
3521 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3522 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3524 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3526 if (param_class->has_references)
3527 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3529 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3531 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3536 * mono_nullable_box:
3537 * @buf: The buffer representing the data to be boxed
3538 * @klass: the type to box it as.
3540 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3544 mono_nullable_box (guint8 *buf, MonoClass *klass)
3546 MONO_REQ_GC_UNSAFE_MODE;
3548 MonoClass *param_class = klass->cast_class;
3550 mono_class_setup_fields_locking (klass);
3551 g_assert (klass->fields_inited);
3553 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3554 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3556 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3557 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3558 if (param_class->has_references)
3559 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3561 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3569 * mono_get_delegate_invoke:
3570 * @klass: The delegate class
3572 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3575 mono_get_delegate_invoke (MonoClass *klass)
3577 MONO_REQ_GC_NEUTRAL_MODE;
3581 /* This is called at runtime, so avoid the slower search in metadata */
3582 mono_class_setup_methods (klass);
3583 if (klass->exception_type)
3585 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3590 * mono_get_delegate_begin_invoke:
3591 * @klass: The delegate class
3593 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3596 mono_get_delegate_begin_invoke (MonoClass *klass)
3598 MONO_REQ_GC_NEUTRAL_MODE;
3602 /* This is called at runtime, so avoid the slower search in metadata */
3603 mono_class_setup_methods (klass);
3604 if (klass->exception_type)
3606 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3611 * mono_get_delegate_end_invoke:
3612 * @klass: The delegate class
3614 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3617 mono_get_delegate_end_invoke (MonoClass *klass)
3619 MONO_REQ_GC_NEUTRAL_MODE;
3623 /* This is called at runtime, so avoid the slower search in metadata */
3624 mono_class_setup_methods (klass);
3625 if (klass->exception_type)
3627 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3632 * mono_runtime_delegate_invoke:
3633 * @delegate: pointer to a delegate object.
3634 * @params: parameters for the delegate.
3635 * @exc: Pointer to the exception result.
3637 * Invokes the delegate method @delegate with the parameters provided.
3639 * You can pass NULL as the exc argument if you don't want to
3640 * catch exceptions, otherwise, *exc will be set to the exception
3641 * thrown, if any. if an exception is thrown, you can't use the
3642 * MonoObject* result from the function.
3645 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3647 MONO_REQ_GC_UNSAFE_MODE;
3650 MonoClass *klass = delegate->vtable->klass;
3652 im = mono_get_delegate_invoke (klass);
3654 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3656 return mono_runtime_invoke (im, delegate, params, exc);
3659 static char **main_args = NULL;
3660 static int num_main_args = 0;
3663 * mono_runtime_get_main_args:
3665 * Returns: a MonoArray with the arguments passed to the main program
3668 mono_runtime_get_main_args (void)
3670 MONO_REQ_GC_UNSAFE_MODE;
3674 MonoDomain *domain = mono_domain_get ();
3676 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3678 for (i = 0; i < num_main_args; ++i)
3679 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3685 free_main_args (void)
3687 MONO_REQ_GC_NEUTRAL_MODE;
3691 for (i = 0; i < num_main_args; ++i)
3692 g_free (main_args [i]);
3699 * mono_runtime_set_main_args:
3700 * @argc: number of arguments from the command line
3701 * @argv: array of strings from the command line
3703 * Set the command line arguments from an embedding application that doesn't otherwise call
3704 * mono_runtime_run_main ().
3707 mono_runtime_set_main_args (int argc, char* argv[])
3709 MONO_REQ_GC_NEUTRAL_MODE;
3714 main_args = g_new0 (char*, argc);
3715 num_main_args = argc;
3717 for (i = 0; i < argc; ++i) {
3720 utf8_arg = mono_utf8_from_external (argv[i]);
3721 if (utf8_arg == NULL) {
3722 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3723 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3727 main_args [i] = utf8_arg;
3734 * mono_runtime_run_main:
3735 * @method: the method to start the application with (usually Main)
3736 * @argc: number of arguments from the command line
3737 * @argv: array of strings from the command line
3738 * @exc: excetption results
3740 * Execute a standard Main() method (argc/argv contains the
3741 * executable name). This method also sets the command line argument value
3742 * needed by System.Environment.
3747 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3750 MONO_REQ_GC_UNSAFE_MODE;
3753 MonoArray *args = NULL;
3754 MonoDomain *domain = mono_domain_get ();
3755 gchar *utf8_fullpath;
3756 MonoMethodSignature *sig;
3758 g_assert (method != NULL);
3760 mono_thread_set_main (mono_thread_current ());
3762 main_args = g_new0 (char*, argc);
3763 num_main_args = argc;
3765 if (!g_path_is_absolute (argv [0])) {
3766 gchar *basename = g_path_get_basename (argv [0]);
3767 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3771 utf8_fullpath = mono_utf8_from_external (fullpath);
3772 if(utf8_fullpath == NULL) {
3773 /* Printing the arg text will cause glib to
3774 * whinge about "Invalid UTF-8", but at least
3775 * its relevant, and shows the problem text
3778 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3779 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3786 utf8_fullpath = mono_utf8_from_external (argv[0]);
3787 if(utf8_fullpath == NULL) {
3788 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3789 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3794 main_args [0] = utf8_fullpath;
3796 for (i = 1; i < argc; ++i) {
3799 utf8_arg=mono_utf8_from_external (argv[i]);
3800 if(utf8_arg==NULL) {
3801 /* Ditto the comment about Invalid UTF-8 here */
3802 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3803 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3807 main_args [i] = utf8_arg;
3812 sig = mono_method_signature (method);
3814 g_print ("Unable to load Main method.\n");
3818 if (sig->param_count) {
3819 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3820 for (i = 0; i < argc; ++i) {
3821 /* The encodings should all work, given that
3822 * we've checked all these args for the
3825 gchar *str = mono_utf8_from_external (argv [i]);
3826 MonoString *arg = mono_string_new (domain, str);
3827 mono_array_setref (args, i, arg);
3831 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3834 mono_assembly_set_main (method->klass->image->assembly);
3836 return mono_runtime_exec_main (method, args, exc);
3840 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3842 static MonoMethod *serialize_method;
3847 if (!serialize_method) {
3848 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3849 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3852 if (!serialize_method) {
3857 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3861 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3869 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3871 MONO_REQ_GC_UNSAFE_MODE;
3873 static MonoMethod *deserialize_method;
3878 if (!deserialize_method) {
3879 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3880 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3882 if (!deserialize_method) {
3889 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3896 #ifndef DISABLE_REMOTING
3898 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3900 MONO_REQ_GC_UNSAFE_MODE;
3902 static MonoMethod *get_proxy_method;
3904 MonoDomain *domain = mono_domain_get ();
3905 MonoRealProxy *real_proxy;
3906 MonoReflectionType *reflection_type;
3907 MonoTransparentProxy *transparent_proxy;
3909 if (!get_proxy_method)
3910 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3912 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3914 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3915 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3917 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3918 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3921 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3925 return (MonoObject*) transparent_proxy;
3927 #endif /* DISABLE_REMOTING */
3930 * mono_object_xdomain_representation
3932 * @target_domain: a domain
3933 * @exc: pointer to a MonoObject*
3935 * Creates a representation of obj in the domain target_domain. This
3936 * is either a copy of obj arrived through via serialization and
3937 * deserialization or a proxy, depending on whether the object is
3938 * serializable or marshal by ref. obj must not be in target_domain.
3940 * If the object cannot be represented in target_domain, NULL is
3941 * returned and *exc is set to an appropriate exception.
3944 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3946 MONO_REQ_GC_UNSAFE_MODE;
3948 MonoObject *deserialized = NULL;
3949 gboolean failure = FALSE;
3953 #ifndef DISABLE_REMOTING
3954 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3955 deserialized = make_transparent_proxy (obj, &failure, exc);
3960 MonoDomain *domain = mono_domain_get ();
3961 MonoObject *serialized;
3963 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3964 serialized = serialize_object (obj, &failure, exc);
3965 mono_domain_set_internal_with_options (target_domain, FALSE);
3967 deserialized = deserialize_object (serialized, &failure, exc);
3968 if (domain != target_domain)
3969 mono_domain_set_internal_with_options (domain, FALSE);
3972 return deserialized;
3975 /* Used in call_unhandled_exception_delegate */
3977 create_unhandled_exception_eventargs (MonoObject *exc)
3979 MONO_REQ_GC_UNSAFE_MODE;
3983 MonoMethod *method = NULL;
3984 MonoBoolean is_terminating = TRUE;
3987 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3990 mono_class_init (klass);
3992 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3993 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3997 args [1] = &is_terminating;
3999 obj = mono_object_new (mono_domain_get (), klass);
4000 mono_runtime_invoke (method, obj, args, NULL);
4005 /* Used in mono_unhandled_exception */
4007 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4008 MONO_REQ_GC_UNSAFE_MODE;
4010 MonoObject *e = NULL;
4012 MonoDomain *current_domain = mono_domain_get ();
4014 if (domain != current_domain)
4015 mono_domain_set_internal_with_options (domain, FALSE);
4017 g_assert (domain == mono_object_domain (domain->domain));
4019 if (mono_object_domain (exc) != domain) {
4020 MonoObject *serialization_exc;
4022 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4024 if (serialization_exc) {
4026 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4029 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4030 "System.Runtime.Serialization", "SerializationException",
4031 "Could not serialize unhandled exception.");
4035 g_assert (mono_object_domain (exc) == domain);
4037 pa [0] = domain->domain;
4038 pa [1] = create_unhandled_exception_eventargs (exc);
4039 mono_runtime_delegate_invoke (delegate, pa, &e);
4041 if (domain != current_domain)
4042 mono_domain_set_internal_with_options (current_domain, FALSE);
4046 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4047 if (!mono_error_ok (&error)) {
4048 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4049 mono_error_cleanup (&error);
4051 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4057 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4060 * mono_runtime_unhandled_exception_policy_set:
4061 * @policy: the new policy
4063 * This is a VM internal routine.
4065 * Sets the runtime policy for handling unhandled exceptions.
4068 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4069 runtime_unhandled_exception_policy = policy;
4073 * mono_runtime_unhandled_exception_policy_get:
4075 * This is a VM internal routine.
4077 * Gets the runtime policy for handling unhandled exceptions.
4079 MonoRuntimeUnhandledExceptionPolicy
4080 mono_runtime_unhandled_exception_policy_get (void) {
4081 return runtime_unhandled_exception_policy;
4085 * mono_unhandled_exception:
4086 * @exc: exception thrown
4088 * This is a VM internal routine.
4090 * We call this function when we detect an unhandled exception
4091 * in the default domain.
4093 * It invokes the * UnhandledException event in AppDomain or prints
4094 * a warning to the console
4097 mono_unhandled_exception (MonoObject *exc)
4099 MONO_REQ_GC_UNSAFE_MODE;
4101 MonoClassField *field;
4102 MonoDomain *current_domain, *root_domain;
4103 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4105 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4108 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4111 current_domain = mono_domain_get ();
4112 root_domain = mono_get_root_domain ();
4114 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4115 if (current_domain != root_domain)
4116 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4118 /* set exitcode only if we will abort the process */
4119 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4120 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4121 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4123 mono_environment_exitcode_set (1);
4126 mono_print_unhandled_exception (exc);
4128 if (root_appdomain_delegate)
4129 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4130 if (current_appdomain_delegate)
4131 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4136 * mono_runtime_exec_managed_code:
4137 * @domain: Application domain
4138 * @main_func: function to invoke from the execution thread
4139 * @main_args: parameter to the main_func
4141 * Launch a new thread to execute a function
4143 * main_func is called back from the thread with main_args as the
4144 * parameter. The callback function is expected to start Main()
4145 * eventually. This function then waits for all managed threads to
4147 * It is not necesseray anymore to execute managed code in a subthread,
4148 * so this function should not be used anymore by default: just
4149 * execute the code and then call mono_thread_manage ().
4152 mono_runtime_exec_managed_code (MonoDomain *domain,
4153 MonoMainThreadFunc main_func,
4156 mono_thread_create (domain, main_func, main_args);
4158 mono_thread_manage ();
4162 * Execute a standard Main() method (args doesn't contain the
4166 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4168 MONO_REQ_GC_UNSAFE_MODE;
4173 MonoCustomAttrInfo* cinfo;
4174 gboolean has_stathread_attribute;
4175 MonoInternalThread* thread = mono_thread_internal_current ();
4181 domain = mono_object_domain (args);
4182 if (!domain->entry_assembly) {
4184 MonoAssembly *assembly;
4186 assembly = method->klass->image->assembly;
4187 domain->entry_assembly = assembly;
4188 /* Domains created from another domain already have application_base and configuration_file set */
4189 if (domain->setup->application_base == NULL) {
4190 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4193 if (domain->setup->configuration_file == NULL) {
4194 str = g_strconcat (assembly->image->name, ".config", NULL);
4195 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4197 mono_domain_set_options_from_config (domain);
4201 cinfo = mono_custom_attrs_from_method (method);
4203 static MonoClass *stathread_attribute = NULL;
4204 if (!stathread_attribute)
4205 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4206 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4208 mono_custom_attrs_free (cinfo);
4210 has_stathread_attribute = FALSE;
4212 if (has_stathread_attribute) {
4213 thread->apartment_state = ThreadApartmentState_STA;
4215 thread->apartment_state = ThreadApartmentState_MTA;
4217 mono_thread_init_apartment_state ();
4219 /* FIXME: check signature of method */
4220 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4222 res = mono_runtime_invoke (method, NULL, pa, exc);
4224 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4228 mono_environment_exitcode_set (rval);
4230 mono_runtime_invoke (method, NULL, pa, exc);
4234 /* If the return type of Main is void, only
4235 * set the exitcode if an exception was thrown
4236 * (we don't want to blow away an
4237 * explicitly-set exit code)
4240 mono_environment_exitcode_set (rval);
4248 * mono_install_runtime_invoke:
4249 * @func: Function to install
4251 * This is a VM internal routine
4254 mono_install_runtime_invoke (MonoInvokeFunc func)
4256 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4261 * mono_runtime_invoke_array:
4262 * @method: method to invoke
4263 * @obJ: object instance
4264 * @params: arguments to the method
4265 * @exc: exception information.
4267 * Invokes the method represented by @method on the object @obj.
4269 * obj is the 'this' pointer, it should be NULL for static
4270 * methods, a MonoObject* for object instances and a pointer to
4271 * the value type for value types.
4273 * The params array contains the arguments to the method with the
4274 * same convention: MonoObject* pointers for object instances and
4275 * pointers to the value type otherwise. The _invoke_array
4276 * variant takes a C# object[] as the params argument (MonoArray
4277 * *params): in this case the value types are boxed inside the
4278 * respective reference representation.
4280 * From unmanaged code you'll usually use the
4281 * mono_runtime_invoke() variant.
4283 * Note that this function doesn't handle virtual methods for
4284 * you, it will exec the exact method you pass: we still need to
4285 * expose a function to lookup the derived class implementation
4286 * of a virtual method (there are examples of this in the code,
4289 * You can pass NULL as the exc argument if you don't want to
4290 * catch exceptions, otherwise, *exc will be set to the exception
4291 * thrown, if any. if an exception is thrown, you can't use the
4292 * MonoObject* result from the function.
4294 * If the method returns a value type, it is boxed in an object
4298 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4301 MONO_REQ_GC_UNSAFE_MODE;
4303 MonoMethodSignature *sig = mono_method_signature (method);
4304 gpointer *pa = NULL;
4307 gboolean has_byref_nullables = FALSE;
4309 if (NULL != params) {
4310 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4311 for (i = 0; i < mono_array_length (params); i++) {
4312 MonoType *t = sig->params [i];
4318 case MONO_TYPE_BOOLEAN:
4321 case MONO_TYPE_CHAR:
4330 case MONO_TYPE_VALUETYPE:
4331 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4332 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4333 pa [i] = mono_array_get (params, MonoObject*, i);
4335 has_byref_nullables = TRUE;
4337 /* MS seems to create the objects if a null is passed in */
4338 if (!mono_array_get (params, MonoObject*, i))
4339 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4343 * We can't pass the unboxed vtype byref to the callee, since
4344 * that would mean the callee would be able to modify boxed
4345 * primitive types. So we (and MS) make a copy of the boxed
4346 * object, pass that to the callee, and replace the original
4347 * boxed object in the arg array with the copy.
4349 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4350 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4351 mono_array_setref (params, i, copy);
4354 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4357 case MONO_TYPE_STRING:
4358 case MONO_TYPE_OBJECT:
4359 case MONO_TYPE_CLASS:
4360 case MONO_TYPE_ARRAY:
4361 case MONO_TYPE_SZARRAY:
4363 pa [i] = mono_array_addr (params, MonoObject*, i);
4364 // FIXME: I need to check this code path
4366 pa [i] = mono_array_get (params, MonoObject*, i);
4368 case MONO_TYPE_GENERICINST:
4370 t = &t->data.generic_class->container_class->this_arg;
4372 t = &t->data.generic_class->container_class->byval_arg;
4374 case MONO_TYPE_PTR: {
4377 /* The argument should be an IntPtr */
4378 arg = mono_array_get (params, MonoObject*, i);
4382 g_assert (arg->vtable->klass == mono_defaults.int_class);
4383 pa [i] = ((MonoIntPtr*)arg)->m_value;
4388 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4393 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4396 if (mono_class_is_nullable (method->klass)) {
4397 /* Need to create a boxed vtype instead */
4403 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4407 obj = mono_object_new (mono_domain_get (), method->klass);
4408 g_assert (obj); /*maybe we should raise a TLE instead?*/
4409 #ifndef DISABLE_REMOTING
4410 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4411 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4414 if (method->klass->valuetype)
4415 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4418 } else if (method->klass->valuetype) {
4419 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4422 mono_runtime_invoke (method, o, pa, exc);
4423 return (MonoObject *)obj;
4425 if (mono_class_is_nullable (method->klass)) {
4426 MonoObject *nullable;
4428 /* Convert the unboxed vtype into a Nullable structure */
4429 nullable = mono_object_new (mono_domain_get (), method->klass);
4431 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4432 obj = mono_object_unbox (nullable);
4435 /* obj must be already unboxed if needed */
4436 res = mono_runtime_invoke (method, obj, pa, exc);
4438 if (sig->ret->type == MONO_TYPE_PTR) {
4439 MonoClass *pointer_class;
4440 static MonoMethod *box_method;
4442 MonoObject *box_exc;
4445 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4446 * convert it to a Pointer object.
4448 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4450 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4452 g_assert (res->vtable->klass == mono_defaults.int_class);
4453 box_args [0] = ((MonoIntPtr*)res)->m_value;
4454 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4455 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4456 g_assert (!box_exc);
4459 if (has_byref_nullables) {
4461 * The runtime invoke wrapper already converted byref nullables back,
4462 * and stored them in pa, we just need to copy them back to the
4465 for (i = 0; i < mono_array_length (params); i++) {
4466 MonoType *t = sig->params [i];
4468 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4469 mono_array_setref (params, i, pa [i]);
4479 * @klass: the class of the object that we want to create
4481 * Returns: a newly created object whose definition is
4482 * looked up using @klass. This will not invoke any constructors,
4483 * so the consumer of this routine has to invoke any constructors on
4484 * its own to initialize the object.
4486 * It returns NULL on failure.
4489 mono_object_new (MonoDomain *domain, MonoClass *klass)
4491 MONO_REQ_GC_UNSAFE_MODE;
4495 vtable = mono_class_vtable (domain, klass);
4500 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4501 mono_error_raise_exception (&error); /* FIXME don't raise here */
4507 * mono_object_new_pinned:
4509 * Same as mono_object_new, but the returned object will be pinned.
4510 * For SGEN, these objects will only be freed at appdomain unload.
4513 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4515 MONO_REQ_GC_UNSAFE_MODE;
4519 mono_error_init (error);
4521 vtable = mono_class_vtable (domain, klass);
4522 g_assert (vtable); /* FIXME don't swallow the error */
4524 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4526 if (G_UNLIKELY (!o))
4527 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4528 else if (G_UNLIKELY (vtable->klass->has_finalize))
4529 mono_object_register_finalizer (o);
4535 * mono_object_new_specific:
4536 * @vtable: the vtable of the object that we want to create
4538 * Returns: A newly created object with class and domain specified
4542 mono_object_new_specific (MonoVTable *vtable)
4545 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4546 mono_error_raise_exception (&error);
4552 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4554 MONO_REQ_GC_UNSAFE_MODE;
4558 mono_error_init (error);
4560 /* check for is_com_object for COM Interop */
4561 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4564 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4567 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4570 mono_class_init (klass);
4572 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4574 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4577 vtable->domain->create_proxy_for_type_method = im;
4580 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4582 o = mono_runtime_invoke (im, NULL, pa, NULL);
4583 if (o != NULL) return o;
4586 return mono_object_new_alloc_specific_checked (vtable, error);
4590 ves_icall_object_new_specific (MonoVTable *vtable)
4593 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4594 mono_error_raise_exception (&error);
4600 mono_object_new_alloc_specific (MonoVTable *vtable)
4603 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4604 mono_error_raise_exception (&error);
4610 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4612 MONO_REQ_GC_UNSAFE_MODE;
4616 mono_error_init (error);
4618 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4620 if (G_UNLIKELY (!o))
4621 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4622 else if (G_UNLIKELY (vtable->klass->has_finalize))
4623 mono_object_register_finalizer (o);
4629 mono_object_new_fast (MonoVTable *vtable)
4632 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4633 mono_error_raise_exception (&error);
4639 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4641 MONO_REQ_GC_UNSAFE_MODE;
4645 mono_error_init (error);
4647 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4649 if (G_UNLIKELY (!o))
4650 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4656 ves_icall_object_new_fast (MonoVTable *vtable)
4659 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4660 mono_error_raise_exception (&error);
4666 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4668 MONO_REQ_GC_UNSAFE_MODE;
4672 mono_error_init (error);
4674 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4676 if (G_UNLIKELY (!o))
4677 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4678 else if (G_UNLIKELY (vtable->klass->has_finalize))
4679 mono_object_register_finalizer (o);
4685 * mono_class_get_allocation_ftn:
4687 * @for_box: the object will be used for boxing
4688 * @pass_size_in_words:
4690 * Return the allocation function appropriate for the given class.
4694 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4696 MONO_REQ_GC_NEUTRAL_MODE;
4698 *pass_size_in_words = FALSE;
4700 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4701 return ves_icall_object_new_specific;
4703 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4705 return ves_icall_object_new_fast;
4708 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4709 * of the overhead of parameter passing.
4712 *pass_size_in_words = TRUE;
4713 #ifdef GC_REDIRECT_TO_LOCAL
4714 return GC_local_gcj_fast_malloc;
4716 return GC_gcj_fast_malloc;
4721 return ves_icall_object_new_specific;
4725 * mono_object_new_from_token:
4726 * @image: Context where the type_token is hosted
4727 * @token: a token of the type that we want to create
4729 * Returns: A newly created object whose definition is
4730 * looked up using @token in the @image image
4733 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4735 MONO_REQ_GC_UNSAFE_MODE;
4740 klass = mono_class_get_checked (image, token, &error);
4741 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4743 return mono_object_new (domain, klass);
4748 * mono_object_clone:
4749 * @obj: the object to clone
4751 * Returns: A newly created object who is a shallow copy of @obj
4754 mono_object_clone (MonoObject *obj)
4757 MonoObject *o = mono_object_clone_checked (obj, &error);
4758 mono_error_raise_exception (&error);
4764 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4766 MONO_REQ_GC_UNSAFE_MODE;
4771 mono_error_init (error);
4773 size = obj->vtable->klass->instance_size;
4775 if (obj->vtable->klass->rank)
4776 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4778 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4780 if (G_UNLIKELY (!o)) {
4781 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4785 /* If the object doesn't contain references this will do a simple memmove. */
4786 mono_gc_wbarrier_object_copy (o, obj);
4788 if (obj->vtable->klass->has_finalize)
4789 mono_object_register_finalizer (o);
4794 * mono_array_full_copy:
4795 * @src: source array to copy
4796 * @dest: destination array
4798 * Copies the content of one array to another with exactly the same type and size.
4801 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4803 MONO_REQ_GC_UNSAFE_MODE;
4806 MonoClass *klass = src->obj.vtable->klass;
4808 g_assert (klass == dest->obj.vtable->klass);
4810 size = mono_array_length (src);
4811 g_assert (size == mono_array_length (dest));
4812 size *= mono_array_element_size (klass);
4814 if (klass->element_class->valuetype) {
4815 if (klass->element_class->has_references)
4816 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4818 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4820 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4823 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4828 * mono_array_clone_in_domain:
4829 * @domain: the domain in which the array will be cloned into
4830 * @array: the array to clone
4832 * This routine returns a copy of the array that is hosted on the
4833 * specified MonoDomain.
4836 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4838 MONO_REQ_GC_UNSAFE_MODE;
4844 MonoClass *klass = array->obj.vtable->klass;
4846 if (array->bounds == NULL) {
4847 size = mono_array_length (array);
4848 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
4849 mono_error_raise_exception (&error); /* FIXME don't raise here */
4851 size *= mono_array_element_size (klass);
4853 if (klass->element_class->valuetype) {
4854 if (klass->element_class->has_references)
4855 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4857 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4859 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4862 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4867 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4868 size = mono_array_element_size (klass);
4869 for (i = 0; i < klass->rank; ++i) {
4870 sizes [i] = array->bounds [i].length;
4871 size *= array->bounds [i].length;
4872 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4874 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
4875 mono_error_raise_exception (&error); /* FIXME don't raise here */
4877 if (klass->element_class->valuetype) {
4878 if (klass->element_class->has_references)
4879 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4881 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4883 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4886 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4894 * @array: the array to clone
4896 * Returns: A newly created array who is a shallow copy of @array
4899 mono_array_clone (MonoArray *array)
4901 MONO_REQ_GC_UNSAFE_MODE;
4903 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4906 /* helper macros to check for overflow when calculating the size of arrays */
4907 #ifdef MONO_BIG_ARRAYS
4908 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4909 #define MYGUINT_MAX MYGUINT64_MAX
4910 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4911 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4912 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4913 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4914 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4916 #define MYGUINT32_MAX 4294967295U
4917 #define MYGUINT_MAX MYGUINT32_MAX
4918 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4919 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4920 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4921 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4922 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4926 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4928 MONO_REQ_GC_NEUTRAL_MODE;
4932 byte_len = mono_array_element_size (klass);
4933 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4936 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4938 byte_len += MONO_SIZEOF_MONO_ARRAY;
4946 * mono_array_new_full:
4947 * @domain: domain where the object is created
4948 * @array_class: array class
4949 * @lengths: lengths for each dimension in the array
4950 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4952 * This routine creates a new array objects with the given dimensions,
4953 * lower bounds and type.
4956 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4959 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
4960 mono_error_raise_exception (&error);
4966 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
4968 MONO_REQ_GC_UNSAFE_MODE;
4970 uintptr_t byte_len = 0, len, bounds_size;
4973 MonoArrayBounds *bounds;
4977 mono_error_init (error);
4979 if (!array_class->inited)
4980 mono_class_init (array_class);
4984 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4985 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4987 if (len > MONO_ARRAY_MAX_INDEX) {
4988 mono_error_set_generic_error (error, "System", "OverflowException", "");
4993 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4995 for (i = 0; i < array_class->rank; ++i) {
4996 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
4997 mono_error_set_generic_error (error, "System", "OverflowException", "");
5000 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5001 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5008 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5009 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5015 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5016 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5019 byte_len = (byte_len + 3) & ~3;
5020 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5021 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5024 byte_len += bounds_size;
5027 * Following three lines almost taken from mono_object_new ():
5028 * they need to be kept in sync.
5030 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5032 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5034 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5036 if (G_UNLIKELY (!o)) {
5037 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5041 array = (MonoArray*)o;
5043 bounds = array->bounds;
5046 for (i = 0; i < array_class->rank; ++i) {
5047 bounds [i].length = lengths [i];
5049 bounds [i].lower_bound = lower_bounds [i];
5058 * @domain: domain where the object is created
5059 * @eclass: element class
5060 * @n: number of array elements
5062 * This routine creates a new szarray with @n elements of type @eclass.
5065 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5067 MONO_REQ_GC_UNSAFE_MODE;
5073 ac = mono_array_class_get (eclass, 1);
5076 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5077 mono_error_raise_exception (&error); /* FIXME don't raise here */
5083 * mono_array_new_specific:
5084 * @vtable: a vtable in the appropriate domain for an initialized class
5085 * @n: number of array elements
5087 * This routine is a fast alternative to mono_array_new() for code which
5088 * can be sure about the domain it operates in.
5091 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5094 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5095 mono_error_raise_exception (&error); /* FIXME don't raise here */
5101 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5103 MONO_REQ_GC_UNSAFE_MODE;
5108 mono_error_init (error);
5110 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5111 mono_error_set_generic_error (error, "System", "OverflowException", "");
5115 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5116 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5119 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5121 if (G_UNLIKELY (!o)) {
5122 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5126 return (MonoArray*)o;
5130 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5133 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5134 mono_error_raise_exception (&error);
5140 * mono_string_new_utf16:
5141 * @text: a pointer to an utf16 string
5142 * @len: the length of the string
5144 * Returns: A newly created string object which contains @text.
5147 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5149 MONO_REQ_GC_UNSAFE_MODE;
5154 s = mono_string_new_size_checked (domain, len, &error);
5155 mono_error_raise_exception (&error); /* FIXME don't raise here */
5157 memcpy (mono_string_chars (s), text, len * 2);
5163 * mono_string_new_utf32:
5164 * @text: a pointer to an utf32 string
5165 * @len: the length of the string
5167 * Returns: A newly created string object which contains @text.
5170 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5172 MONO_REQ_GC_UNSAFE_MODE;
5176 mono_unichar2 *utf16_output = NULL;
5177 gint32 utf16_len = 0;
5178 GError *gerror = NULL;
5179 glong items_written;
5181 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5184 g_error_free (gerror);
5186 while (utf16_output [utf16_len]) utf16_len++;
5188 s = mono_string_new_size_checked (domain, utf16_len, &error);
5189 mono_error_raise_exception (&error); /* FIXME don't raise here */
5191 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5193 g_free (utf16_output);
5199 * mono_string_new_size:
5200 * @text: a pointer to an utf16 string
5201 * @len: the length of the string
5203 * Returns: A newly created string object of @len
5206 mono_string_new_size (MonoDomain *domain, gint32 len)
5209 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5210 mono_error_raise_exception (&error);
5216 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5218 MONO_REQ_GC_UNSAFE_MODE;
5224 mono_error_init (error);
5226 /* check for overflow */
5227 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5228 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5232 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5233 g_assert (size > 0);
5235 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5238 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5240 if (G_UNLIKELY (!s)) {
5241 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5249 * mono_string_new_len:
5250 * @text: a pointer to an utf8 string
5251 * @length: number of bytes in @text to consider
5253 * Returns: A newly created string object which contains @text.
5256 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5258 MONO_REQ_GC_UNSAFE_MODE;
5260 GError *error = NULL;
5261 MonoString *o = NULL;
5263 glong items_written;
5265 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5268 o = mono_string_new_utf16 (domain, ut, items_written);
5270 g_error_free (error);
5279 * @text: a pointer to an utf8 string
5281 * Returns: A newly created string object which contains @text.
5284 mono_string_new (MonoDomain *domain, const char *text)
5286 MONO_REQ_GC_UNSAFE_MODE;
5288 GError *error = NULL;
5289 MonoString *o = NULL;
5291 glong items_written;
5296 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5299 o = mono_string_new_utf16 (domain, ut, items_written);
5301 g_error_free (error);
5304 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5310 MonoString *o = NULL;
5312 if (!g_utf8_validate (text, -1, &end))
5315 len = g_utf8_strlen (text, -1);
5316 o = mono_string_new_size_checked (domain, len, &error);
5317 mono_error_raise_exception (&error); /* FIXME don't raise here */
5318 str = mono_string_chars (o);
5320 while (text < end) {
5321 *str++ = g_utf8_get_char (text);
5322 text = g_utf8_next_char (text);
5329 * mono_string_new_wrapper:
5330 * @text: pointer to utf8 characters.
5332 * Helper function to create a string object from @text in the current domain.
5335 mono_string_new_wrapper (const char *text)
5337 MONO_REQ_GC_UNSAFE_MODE;
5339 MonoDomain *domain = mono_domain_get ();
5342 return mono_string_new (domain, text);
5349 * @class: the class of the value
5350 * @value: a pointer to the unboxed data
5352 * Returns: A newly created object which contains @value.
5355 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5357 MONO_REQ_GC_UNSAFE_MODE;
5364 g_assert (klass->valuetype);
5365 if (mono_class_is_nullable (klass))
5366 return mono_nullable_box ((guint8 *)value, klass);
5368 vtable = mono_class_vtable (domain, klass);
5371 size = mono_class_instance_size (klass);
5372 res = mono_object_new_alloc_specific_checked (vtable, &error);
5373 mono_error_raise_exception (&error); /* FIXME don't raise here */
5375 size = size - sizeof (MonoObject);
5378 g_assert (size == mono_class_value_size (klass, NULL));
5379 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5381 #if NO_UNALIGNED_ACCESS
5382 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5386 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5389 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5392 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5395 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5398 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5402 if (klass->has_finalize)
5403 mono_object_register_finalizer (res);
5409 * @dest: destination pointer
5410 * @src: source pointer
5411 * @klass: a valuetype class
5413 * Copy a valuetype from @src to @dest. This function must be used
5414 * when @klass contains references fields.
5417 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5419 MONO_REQ_GC_UNSAFE_MODE;
5421 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5425 * mono_value_copy_array:
5426 * @dest: destination array
5427 * @dest_idx: index in the @dest array
5428 * @src: source pointer
5429 * @count: number of items
5431 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5432 * This function must be used when @klass contains references fields.
5433 * Overlap is handled.
5436 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5438 MONO_REQ_GC_UNSAFE_MODE;
5440 int size = mono_array_element_size (dest->obj.vtable->klass);
5441 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5442 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5443 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5447 * mono_object_get_domain:
5448 * @obj: object to query
5450 * Returns: the MonoDomain where the object is hosted
5453 mono_object_get_domain (MonoObject *obj)
5455 MONO_REQ_GC_UNSAFE_MODE;
5457 return mono_object_domain (obj);
5461 * mono_object_get_class:
5462 * @obj: object to query
5464 * Returns: the MonOClass of the object.
5467 mono_object_get_class (MonoObject *obj)
5469 MONO_REQ_GC_UNSAFE_MODE;
5471 return mono_object_class (obj);
5474 * mono_object_get_size:
5475 * @o: object to query
5477 * Returns: the size, in bytes, of @o
5480 mono_object_get_size (MonoObject* o)
5482 MONO_REQ_GC_UNSAFE_MODE;
5484 MonoClass* klass = mono_object_class (o);
5485 if (klass == mono_defaults.string_class) {
5486 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5487 } else if (o->vtable->rank) {
5488 MonoArray *array = (MonoArray*)o;
5489 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5490 if (array->bounds) {
5493 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5497 return mono_class_instance_size (klass);
5502 * mono_object_unbox:
5503 * @obj: object to unbox
5505 * Returns: a pointer to the start of the valuetype boxed in this
5508 * This method will assert if the object passed is not a valuetype.
5511 mono_object_unbox (MonoObject *obj)
5513 MONO_REQ_GC_UNSAFE_MODE;
5515 /* add assert for valuetypes? */
5516 g_assert (obj->vtable->klass->valuetype);
5517 return ((char*)obj) + sizeof (MonoObject);
5521 * mono_object_isinst:
5523 * @klass: a pointer to a class
5525 * Returns: @obj if @obj is derived from @klass
5528 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5530 MONO_REQ_GC_UNSAFE_MODE;
5533 mono_class_init (klass);
5535 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5536 return mono_object_isinst_mbyref (obj, klass);
5541 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5545 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5547 MONO_REQ_GC_UNSAFE_MODE;
5556 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5557 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5561 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5562 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5565 MonoClass *oklass = vt->klass;
5566 if (mono_class_is_transparent_proxy (oklass))
5567 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5569 mono_class_setup_supertypes (klass);
5570 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5573 #ifndef DISABLE_REMOTING
5574 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5576 MonoDomain *domain = mono_domain_get ();
5578 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5579 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5580 MonoMethod *im = NULL;
5583 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5585 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5586 im = mono_object_get_virtual_method (rp, im);
5589 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5592 res = mono_runtime_invoke (im, rp, pa, NULL);
5594 if (*(MonoBoolean *) mono_object_unbox(res)) {
5595 /* Update the vtable of the remote type, so it can safely cast to this new type */
5596 mono_upgrade_remote_class (domain, obj, klass);
5600 #endif /* DISABLE_REMOTING */
5605 * mono_object_castclass_mbyref:
5607 * @klass: a pointer to a class
5609 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5612 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5614 MONO_REQ_GC_UNSAFE_MODE;
5616 if (!obj) return NULL;
5617 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5619 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5621 "InvalidCastException"));
5626 MonoDomain *orig_domain;
5632 str_lookup (MonoDomain *domain, gpointer user_data)
5634 MONO_REQ_GC_UNSAFE_MODE;
5636 LDStrInfo *info = (LDStrInfo *)user_data;
5637 if (info->res || domain == info->orig_domain)
5639 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5643 mono_string_get_pinned (MonoString *str, MonoError *error)
5645 MONO_REQ_GC_UNSAFE_MODE;
5647 mono_error_init (error);
5649 /* We only need to make a pinned version of a string if this is a moving GC */
5650 if (!mono_gc_is_moving ())
5654 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5655 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5657 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5658 news->length = mono_string_length (str);
5660 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5666 mono_string_is_interned_lookup (MonoString *str, int insert)
5668 MONO_REQ_GC_UNSAFE_MODE;
5671 MonoGHashTable *ldstr_table;
5672 MonoString *s, *res;
5675 domain = ((MonoObject *)str)->vtable->domain;
5676 ldstr_table = domain->ldstr_table;
5678 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5684 /* Allocate outside the lock */
5686 s = mono_string_get_pinned (str, &error);
5687 mono_error_raise_exception (&error); /* FIXME don't raise here */
5690 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5695 mono_g_hash_table_insert (ldstr_table, s, s);
5700 LDStrInfo ldstr_info;
5701 ldstr_info.orig_domain = domain;
5702 ldstr_info.ins = str;
5703 ldstr_info.res = NULL;
5705 mono_domain_foreach (str_lookup, &ldstr_info);
5706 if (ldstr_info.res) {
5708 * the string was already interned in some other domain:
5709 * intern it in the current one as well.
5711 mono_g_hash_table_insert (ldstr_table, str, str);
5721 * mono_string_is_interned:
5722 * @o: String to probe
5724 * Returns whether the string has been interned.
5727 mono_string_is_interned (MonoString *o)
5729 MONO_REQ_GC_UNSAFE_MODE;
5731 return mono_string_is_interned_lookup (o, FALSE);
5735 * mono_string_intern:
5736 * @o: String to intern
5738 * Interns the string passed.
5739 * Returns: The interned string.
5742 mono_string_intern (MonoString *str)
5744 MONO_REQ_GC_UNSAFE_MODE;
5746 return mono_string_is_interned_lookup (str, TRUE);
5751 * @domain: the domain where the string will be used.
5752 * @image: a metadata context
5753 * @idx: index into the user string table.
5755 * Implementation for the ldstr opcode.
5756 * Returns: a loaded string from the @image/@idx combination.
5759 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5761 MONO_REQ_GC_UNSAFE_MODE;
5763 if (image->dynamic) {
5764 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5767 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5768 return NULL; /*FIXME we should probably be raising an exception here*/
5769 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5774 * mono_ldstr_metadata_sig
5775 * @domain: the domain for the string
5776 * @sig: the signature of a metadata string
5778 * Returns: a MonoString for a string stored in the metadata
5781 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5783 MONO_REQ_GC_UNSAFE_MODE;
5786 const char *str = sig;
5787 MonoString *o, *interned;
5790 len2 = mono_metadata_decode_blob_size (str, &str);
5793 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5794 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5797 guint16 *p2 = (guint16*)mono_string_chars (o);
5798 for (i = 0; i < len2; ++i) {
5799 *p2 = GUINT16_FROM_LE (*p2);
5805 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5808 return interned; /* o will get garbage collected */
5810 o = mono_string_get_pinned (o, &error);
5811 mono_error_raise_exception (&error); /* FIXME don't raise here */
5814 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5816 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5826 * mono_string_to_utf8:
5827 * @s: a System.String
5829 * Returns the UTF8 representation for @s.
5830 * The resulting buffer needs to be freed with mono_free().
5832 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5835 mono_string_to_utf8 (MonoString *s)
5837 MONO_REQ_GC_UNSAFE_MODE;
5840 char *result = mono_string_to_utf8_checked (s, &error);
5842 if (!mono_error_ok (&error))
5843 mono_error_raise_exception (&error);
5848 * mono_string_to_utf8_checked:
5849 * @s: a System.String
5850 * @error: a MonoError.
5852 * Converts a MonoString to its UTF8 representation. May fail; check
5853 * @error to determine whether the conversion was successful.
5854 * The resulting buffer should be freed with mono_free().
5857 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5859 MONO_REQ_GC_UNSAFE_MODE;
5863 GError *gerror = NULL;
5865 mono_error_init (error);
5871 return g_strdup ("");
5873 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5875 mono_error_set_argument (error, "string", "%s", gerror->message);
5876 g_error_free (gerror);
5879 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5880 if (s->length > written) {
5881 /* allocate the total length and copy the part of the string that has been converted */
5882 char *as2 = (char *)g_malloc0 (s->length);
5883 memcpy (as2, as, written);
5892 * mono_string_to_utf8_ignore:
5895 * Converts a MonoString to its UTF8 representation. Will ignore
5896 * invalid surrogate pairs.
5897 * The resulting buffer should be freed with mono_free().
5901 mono_string_to_utf8_ignore (MonoString *s)
5903 MONO_REQ_GC_UNSAFE_MODE;
5912 return g_strdup ("");
5914 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5916 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5917 if (s->length > written) {
5918 /* allocate the total length and copy the part of the string that has been converted */
5919 char *as2 = (char *)g_malloc0 (s->length);
5920 memcpy (as2, as, written);
5929 * mono_string_to_utf8_image_ignore:
5930 * @s: a System.String
5932 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5935 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5937 MONO_REQ_GC_UNSAFE_MODE;
5939 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5943 * mono_string_to_utf8_mp_ignore:
5944 * @s: a System.String
5946 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5949 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5951 MONO_REQ_GC_UNSAFE_MODE;
5953 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5958 * mono_string_to_utf16:
5961 * Return an null-terminated array of the utf-16 chars
5962 * contained in @s. The result must be freed with g_free().
5963 * This is a temporary helper until our string implementation
5964 * is reworked to always include the null terminating char.
5967 mono_string_to_utf16 (MonoString *s)
5969 MONO_REQ_GC_UNSAFE_MODE;
5976 as = (char *)g_malloc ((s->length * 2) + 2);
5977 as [(s->length * 2)] = '\0';
5978 as [(s->length * 2) + 1] = '\0';
5981 return (gunichar2 *)(as);
5984 memcpy (as, mono_string_chars(s), s->length * 2);
5985 return (gunichar2 *)(as);
5989 * mono_string_to_utf32:
5992 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5993 * contained in @s. The result must be freed with g_free().
5996 mono_string_to_utf32 (MonoString *s)
5998 MONO_REQ_GC_UNSAFE_MODE;
6000 mono_unichar4 *utf32_output = NULL;
6001 GError *error = NULL;
6002 glong items_written;
6007 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6010 g_error_free (error);
6012 return utf32_output;
6016 * mono_string_from_utf16:
6017 * @data: the UTF16 string (LPWSTR) to convert
6019 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6021 * Returns: a MonoString.
6024 mono_string_from_utf16 (gunichar2 *data)
6026 MONO_REQ_GC_UNSAFE_MODE;
6028 MonoDomain *domain = mono_domain_get ();
6034 while (data [len]) len++;
6036 return mono_string_new_utf16 (domain, data, len);
6040 * mono_string_from_utf32:
6041 * @data: the UTF32 string (LPWSTR) to convert
6043 * Converts a UTF32 (UCS-4)to a MonoString.
6045 * Returns: a MonoString.
6048 mono_string_from_utf32 (mono_unichar4 *data)
6050 MONO_REQ_GC_UNSAFE_MODE;
6052 MonoString* result = NULL;
6053 mono_unichar2 *utf16_output = NULL;
6054 GError *error = NULL;
6055 glong items_written;
6061 while (data [len]) len++;
6063 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6066 g_error_free (error);
6068 result = mono_string_from_utf16 (utf16_output);
6069 g_free (utf16_output);
6074 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6076 MONO_REQ_GC_UNSAFE_MODE;
6083 r = mono_string_to_utf8_ignore (s);
6085 r = mono_string_to_utf8_checked (s, error);
6086 if (!mono_error_ok (error))
6093 len = strlen (r) + 1;
6095 mp_s = (char *)mono_mempool_alloc (mp, len);
6097 mp_s = (char *)mono_image_alloc (image, len);
6099 memcpy (mp_s, r, len);
6107 * mono_string_to_utf8_image:
6108 * @s: a System.String
6110 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6113 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6115 MONO_REQ_GC_UNSAFE_MODE;
6117 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6121 * mono_string_to_utf8_mp:
6122 * @s: a System.String
6124 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6127 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6129 MONO_REQ_GC_UNSAFE_MODE;
6131 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6135 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6138 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6140 eh_callbacks = *cbs;
6143 MonoRuntimeExceptionHandlingCallbacks *
6144 mono_get_eh_callbacks (void)
6146 return &eh_callbacks;
6150 * mono_raise_exception:
6151 * @ex: exception object
6153 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6156 mono_raise_exception (MonoException *ex)
6158 MONO_REQ_GC_UNSAFE_MODE;
6161 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6162 * that will cause gcc to omit the function epilog, causing problems when
6163 * the JIT tries to walk the stack, since the return address on the stack
6164 * will point into the next function in the executable, not this one.
6166 eh_callbacks.mono_raise_exception (ex);
6170 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6172 MONO_REQ_GC_UNSAFE_MODE;
6174 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6178 * mono_wait_handle_new:
6179 * @domain: Domain where the object will be created
6180 * @handle: Handle for the wait handle
6182 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6185 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6187 MONO_REQ_GC_UNSAFE_MODE;
6189 MonoWaitHandle *res;
6190 gpointer params [1];
6191 static MonoMethod *handle_set;
6193 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6195 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6197 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6199 params [0] = &handle;
6200 mono_runtime_invoke (handle_set, res, params, NULL);
6206 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6208 MONO_REQ_GC_UNSAFE_MODE;
6210 static MonoClassField *f_os_handle;
6211 static MonoClassField *f_safe_handle;
6213 if (!f_os_handle && !f_safe_handle) {
6214 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6215 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6220 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6224 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6231 mono_runtime_capture_context (MonoDomain *domain)
6233 MONO_REQ_GC_UNSAFE_MODE;
6235 RuntimeInvokeFunction runtime_invoke;
6237 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6238 MonoMethod *method = mono_get_context_capture_method ();
6239 MonoMethod *wrapper;
6242 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6243 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6244 domain->capture_context_method = mono_compile_method (method);
6247 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6249 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6252 * mono_async_result_new:
6253 * @domain:domain where the object will be created.
6254 * @handle: wait handle.
6255 * @state: state to pass to AsyncResult
6256 * @data: C closure data.
6258 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6259 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6263 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6265 MONO_REQ_GC_UNSAFE_MODE;
6267 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6268 MonoObject *context = mono_runtime_capture_context (domain);
6269 /* we must capture the execution context from the original thread */
6271 MONO_OBJECT_SETREF (res, execution_context, context);
6272 /* note: result may be null if the flow is suppressed */
6275 res->data = (void **)data;
6276 MONO_OBJECT_SETREF (res, object_data, object_data);
6277 MONO_OBJECT_SETREF (res, async_state, state);
6279 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6281 res->sync_completed = FALSE;
6282 res->completed = FALSE;
6288 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6290 MONO_REQ_GC_UNSAFE_MODE;
6296 g_assert (ares->async_delegate);
6298 ac = (MonoAsyncCall*) ares->object_data;
6300 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6302 gpointer wait_event = NULL;
6304 ac->msg->exc = NULL;
6305 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6306 MONO_OBJECT_SETREF (ac, res, res);
6308 mono_monitor_enter ((MonoObject*) ares);
6309 ares->completed = 1;
6311 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6312 mono_monitor_exit ((MonoObject*) ares);
6314 if (wait_event != NULL)
6315 SetEvent (wait_event);
6317 if (ac->cb_method) {
6318 /* we swallow the excepton as it is the behavior on .NET */
6319 MonoObject *exc = NULL;
6320 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6322 mono_unhandled_exception (exc);
6330 mono_message_init (MonoDomain *domain,
6331 MonoMethodMessage *this_obj,
6332 MonoReflectionMethod *method,
6333 MonoArray *out_args)
6335 MONO_REQ_GC_UNSAFE_MODE;
6337 static MonoClass *object_array_klass;
6338 static MonoClass *byte_array_klass;
6339 static MonoClass *string_array_klass;
6341 MonoMethodSignature *sig = mono_method_signature (method->method);
6348 if (!object_array_klass) {
6351 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6353 byte_array_klass = klass;
6355 klass = mono_array_class_get (mono_defaults.string_class, 1);
6357 string_array_klass = klass;
6359 klass = mono_array_class_get (mono_defaults.object_class, 1);
6362 mono_atomic_store_release (&object_array_klass, klass);
6365 MONO_OBJECT_SETREF (this_obj, method, method);
6367 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6368 mono_error_raise_exception (&error); /* FIXME don't raise here */
6370 MONO_OBJECT_SETREF (this_obj, args, arr);
6372 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6373 mono_error_raise_exception (&error); /* FIXME don't raise here */
6375 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6377 this_obj->async_result = NULL;
6378 this_obj->call_type = CallType_Sync;
6380 names = g_new (char *, sig->param_count);
6381 mono_method_get_param_names (method->method, (const char **) names);
6383 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6384 mono_error_raise_exception (&error); /* FIXME don't raise here */
6386 MONO_OBJECT_SETREF (this_obj, names, arr);
6388 for (i = 0; i < sig->param_count; i++) {
6389 name = mono_string_new (domain, names [i]);
6390 mono_array_setref (this_obj->names, i, name);
6394 for (i = 0, j = 0; i < sig->param_count; i++) {
6395 if (sig->params [i]->byref) {
6397 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6398 mono_array_setref (this_obj->args, i, arg);
6402 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6406 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6409 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6413 #ifndef DISABLE_REMOTING
6415 * mono_remoting_invoke:
6416 * @real_proxy: pointer to a RealProxy object
6417 * @msg: The MonoMethodMessage to execute
6418 * @exc: used to store exceptions
6419 * @out_args: used to store output arguments
6421 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6422 * IMessage interface and it is not trivial to extract results from there. So
6423 * we call an helper method PrivateInvoke instead of calling
6424 * RealProxy::Invoke() directly.
6426 * Returns: the result object.
6429 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6430 MonoObject **exc, MonoArray **out_args)
6432 MONO_REQ_GC_UNSAFE_MODE;
6434 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6437 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6440 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6442 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6443 real_proxy->vtable->domain->private_invoke_method = im;
6446 pa [0] = real_proxy;
6451 return mono_runtime_invoke (im, NULL, pa, exc);
6456 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6457 MonoObject **exc, MonoArray **out_args)
6459 MONO_REQ_GC_UNSAFE_MODE;
6461 static MonoClass *object_array_klass;
6465 MonoMethodSignature *sig;
6468 int i, j, outarg_count = 0;
6470 #ifndef DISABLE_REMOTING
6471 if (target && mono_object_is_transparent_proxy (target)) {
6472 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6473 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6474 target = tp->rp->unwrapped_server;
6476 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6481 domain = mono_domain_get ();
6482 method = msg->method->method;
6483 sig = mono_method_signature (method);
6485 for (i = 0; i < sig->param_count; i++) {
6486 if (sig->params [i]->byref)
6490 if (!object_array_klass) {
6493 klass = mono_array_class_get (mono_defaults.object_class, 1);
6496 mono_memory_barrier ();
6497 object_array_klass = klass;
6500 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6501 mono_error_raise_exception (&error); /* FIXME don't raise here */
6503 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6506 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6508 for (i = 0, j = 0; i < sig->param_count; i++) {
6509 if (sig->params [i]->byref) {
6511 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6512 mono_array_setref (*out_args, j, arg);
6521 * mono_object_to_string:
6523 * @exc: Any exception thrown by ToString (). May be NULL.
6525 * Returns: the result of calling ToString () on an object.
6528 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6530 MONO_REQ_GC_UNSAFE_MODE;
6532 static MonoMethod *to_string = NULL;
6539 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6541 method = mono_object_get_virtual_method (obj, to_string);
6543 // Unbox value type if needed
6544 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6545 target = mono_object_unbox (obj);
6548 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6552 * mono_print_unhandled_exception:
6553 * @exc: The exception
6555 * Prints the unhandled exception.
6558 mono_print_unhandled_exception (MonoObject *exc)
6560 MONO_REQ_GC_UNSAFE_MODE;
6563 char *message = (char*)"";
6564 gboolean free_message = FALSE;
6567 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6568 message = g_strdup ("OutOfMemoryException");
6569 free_message = TRUE;
6570 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6571 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6572 free_message = TRUE;
6575 if (((MonoException*)exc)->native_trace_ips) {
6576 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6577 free_message = TRUE;
6579 MonoObject *other_exc = NULL;
6580 str = mono_object_to_string (exc, &other_exc);
6582 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6583 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6585 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6586 original_backtrace, nested_backtrace);
6588 g_free (original_backtrace);
6589 g_free (nested_backtrace);
6590 free_message = TRUE;
6592 message = mono_string_to_utf8_checked (str, &error);
6593 if (!mono_error_ok (&error)) {
6594 mono_error_cleanup (&error);
6595 message = (char *) "";
6597 free_message = TRUE;
6604 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6605 * exc->vtable->klass->name, message);
6607 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6614 * mono_delegate_ctor:
6615 * @this: pointer to an uninitialized delegate object
6616 * @target: target object
6617 * @addr: pointer to native code
6620 * Initialize a delegate and sets a specific method, not the one
6621 * associated with addr. This is useful when sharing generic code.
6622 * In that case addr will most probably not be associated with the
6623 * correct instantiation of the method.
6626 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6628 MONO_REQ_GC_UNSAFE_MODE;
6630 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6632 g_assert (this_obj);
6635 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6638 delegate->method = method;
6640 mono_stats.delegate_creations++;
6642 #ifndef DISABLE_REMOTING
6643 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6645 method = mono_marshal_get_remoting_invoke (method);
6646 delegate->method_ptr = mono_compile_method (method);
6647 MONO_OBJECT_SETREF (delegate, target, target);
6651 delegate->method_ptr = addr;
6652 MONO_OBJECT_SETREF (delegate, target, target);
6655 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6656 if (callbacks.init_delegate)
6657 callbacks.init_delegate (delegate);
6661 * mono_delegate_ctor:
6662 * @this: pointer to an uninitialized delegate object
6663 * @target: target object
6664 * @addr: pointer to native code
6666 * This is used to initialize a delegate.
6669 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6671 MONO_REQ_GC_UNSAFE_MODE;
6673 MonoDomain *domain = mono_domain_get ();
6675 MonoMethod *method = NULL;
6679 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6681 if (!ji && domain != mono_get_root_domain ())
6682 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6684 method = mono_jit_info_get_method (ji);
6685 g_assert (!method->klass->generic_container);
6688 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6692 * mono_method_call_message_new:
6693 * @method: method to encapsulate
6694 * @params: parameters to the method
6695 * @invoke: optional, delegate invoke.
6696 * @cb: async callback delegate.
6697 * @state: state passed to the async callback.
6699 * Translates arguments pointers into a MonoMethodMessage.
6702 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6703 MonoDelegate **cb, MonoObject **state)
6705 MONO_REQ_GC_UNSAFE_MODE;
6707 MonoDomain *domain = mono_domain_get ();
6708 MonoMethodSignature *sig = mono_method_signature (method);
6709 MonoMethodMessage *msg;
6712 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6715 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6716 count = sig->param_count - 2;
6718 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6719 count = sig->param_count;
6722 for (i = 0; i < count; i++) {
6727 if (sig->params [i]->byref)
6728 vpos = *((gpointer *)params [i]);
6732 klass = mono_class_from_mono_type (sig->params [i]);
6734 if (klass->valuetype)
6735 arg = mono_value_box (domain, klass, vpos);
6737 arg = *((MonoObject **)vpos);
6739 mono_array_setref (msg->args, i, arg);
6742 if (cb != NULL && state != NULL) {
6743 *cb = *((MonoDelegate **)params [i]);
6745 *state = *((MonoObject **)params [i]);
6752 * mono_method_return_message_restore:
6754 * Restore results from message based processing back to arguments pointers
6757 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6759 MONO_REQ_GC_UNSAFE_MODE;
6761 MonoMethodSignature *sig = mono_method_signature (method);
6762 int i, j, type, size, out_len;
6764 if (out_args == NULL)
6766 out_len = mono_array_length (out_args);
6770 for (i = 0, j = 0; i < sig->param_count; i++) {
6771 MonoType *pt = sig->params [i];
6776 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6778 arg = (char *)mono_array_get (out_args, gpointer, j);
6781 g_assert (type != MONO_TYPE_VOID);
6783 if (MONO_TYPE_IS_REFERENCE (pt)) {
6784 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6787 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6788 size = mono_class_value_size (klass, NULL);
6789 if (klass->has_references)
6790 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6792 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6794 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6795 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6804 #ifndef DISABLE_REMOTING
6807 * mono_load_remote_field:
6808 * @this: pointer to an object
6809 * @klass: klass of the object containing @field
6810 * @field: the field to load
6811 * @res: a storage to store the result
6813 * This method is called by the runtime on attempts to load fields of
6814 * transparent proxy objects. @this points to such TP, @klass is the class of
6815 * the object containing @field. @res is a storage location which can be
6816 * used to store the result.
6818 * Returns: an address pointing to the value of field.
6821 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6823 MONO_REQ_GC_UNSAFE_MODE;
6825 static MonoMethod *getter = NULL;
6826 MonoDomain *domain = mono_domain_get ();
6827 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6828 MonoClass *field_class;
6829 MonoMethodMessage *msg;
6830 MonoArray *out_args;
6834 g_assert (mono_object_is_transparent_proxy (this_obj));
6835 g_assert (res != NULL);
6837 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6838 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6843 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6845 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6848 field_class = mono_class_from_mono_type (field->type);
6850 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6851 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6852 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6854 full_name = mono_type_get_full_name (klass);
6855 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6856 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6859 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6861 if (exc) mono_raise_exception ((MonoException *)exc);
6863 if (mono_array_length (out_args) == 0)
6866 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6868 if (field_class->valuetype) {
6869 return ((char *)*res) + sizeof (MonoObject);
6875 * mono_load_remote_field_new:
6880 * Missing documentation.
6883 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6885 MONO_REQ_GC_UNSAFE_MODE;
6887 static MonoMethod *getter = NULL;
6888 MonoDomain *domain = mono_domain_get ();
6889 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6890 MonoClass *field_class;
6891 MonoMethodMessage *msg;
6892 MonoArray *out_args;
6893 MonoObject *exc, *res;
6896 g_assert (mono_object_is_transparent_proxy (this_obj));
6898 field_class = mono_class_from_mono_type (field->type);
6900 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6902 if (field_class->valuetype) {
6903 res = mono_object_new (domain, field_class);
6904 val = ((gchar *) res) + sizeof (MonoObject);
6908 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6913 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6915 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6918 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6919 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6921 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6923 full_name = mono_type_get_full_name (klass);
6924 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6925 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6928 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6930 if (exc) mono_raise_exception ((MonoException *)exc);
6932 if (mono_array_length (out_args) == 0)
6935 res = mono_array_get (out_args, MonoObject *, 0);
6941 * mono_store_remote_field:
6942 * @this_obj: pointer to an object
6943 * @klass: klass of the object containing @field
6944 * @field: the field to load
6945 * @val: the value/object to store
6947 * This method is called by the runtime on attempts to store fields of
6948 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6949 * the object containing @field. @val is the new value to store in @field.
6952 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6954 MONO_REQ_GC_UNSAFE_MODE;
6956 static MonoMethod *setter = NULL;
6957 MonoDomain *domain = mono_domain_get ();
6958 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6959 MonoClass *field_class;
6960 MonoMethodMessage *msg;
6961 MonoArray *out_args;
6966 g_assert (mono_object_is_transparent_proxy (this_obj));
6968 field_class = mono_class_from_mono_type (field->type);
6970 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6971 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6972 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6977 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6979 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6982 if (field_class->valuetype)
6983 arg = mono_value_box (domain, field_class, val);
6985 arg = *((MonoObject **)val);
6988 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6989 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6991 full_name = mono_type_get_full_name (klass);
6992 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6993 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6994 mono_array_setref (msg->args, 2, arg);
6997 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6999 if (exc) mono_raise_exception ((MonoException *)exc);
7003 * mono_store_remote_field_new:
7009 * Missing documentation
7012 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7014 MONO_REQ_GC_UNSAFE_MODE;
7016 static MonoMethod *setter = NULL;
7017 MonoDomain *domain = mono_domain_get ();
7018 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7019 MonoClass *field_class;
7020 MonoMethodMessage *msg;
7021 MonoArray *out_args;
7025 g_assert (mono_object_is_transparent_proxy (this_obj));
7027 field_class = mono_class_from_mono_type (field->type);
7029 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7030 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7031 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7036 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7038 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7041 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7042 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7044 full_name = mono_type_get_full_name (klass);
7045 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7046 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7047 mono_array_setref (msg->args, 2, arg);
7050 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7052 if (exc) mono_raise_exception ((MonoException *)exc);
7057 * mono_create_ftnptr:
7059 * Given a function address, create a function descriptor for it.
7060 * This is only needed on some platforms.
7063 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7065 return callbacks.create_ftnptr (domain, addr);
7069 * mono_get_addr_from_ftnptr:
7071 * Given a pointer to a function descriptor, return the function address.
7072 * This is only needed on some platforms.
7075 mono_get_addr_from_ftnptr (gpointer descr)
7077 return callbacks.get_addr_from_ftnptr (descr);
7081 * mono_string_chars:
7084 * Returns a pointer to the UCS16 characters stored in the MonoString
7087 mono_string_chars (MonoString *s)
7089 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7095 * mono_string_length:
7098 * Returns the lenght in characters of the string
7101 mono_string_length (MonoString *s)
7103 MONO_REQ_GC_UNSAFE_MODE;
7109 * mono_array_length:
7110 * @array: a MonoArray*
7112 * Returns the total number of elements in the array. This works for
7113 * both vectors and multidimensional arrays.
7116 mono_array_length (MonoArray *array)
7118 MONO_REQ_GC_UNSAFE_MODE;
7120 return array->max_length;
7124 * mono_array_addr_with_size:
7125 * @array: a MonoArray*
7126 * @size: size of the array elements
7127 * @idx: index into the array
7129 * Returns the address of the @idx element in the array.
7132 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7134 MONO_REQ_GC_UNSAFE_MODE;
7136 return ((char*)(array)->vector) + size * idx;
7141 mono_glist_to_array (GList *list, MonoClass *eclass)
7143 MonoDomain *domain = mono_domain_get ();
7150 len = g_list_length (list);
7151 res = mono_array_new (domain, eclass, len);
7153 for (i = 0; list; list = list->next, i++)
7154 mono_array_set (res, gpointer, i, list->data);