2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internals.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-error-internals.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/checked-build.h>
46 #include <mono/utils/mono-threads.h>
47 #include "cominterop.h"
50 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
53 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
56 free_main_args (void);
59 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
62 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
63 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
64 static mono_mutex_t ldstr_section;
67 mono_runtime_object_init (MonoObject *this_obj)
69 MONO_REQ_GC_UNSAFE_MODE;
71 MonoMethod *method = NULL;
72 MonoClass *klass = this_obj->vtable->klass;
74 method = mono_class_get_method_from_name (klass, ".ctor", 0);
76 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
78 if (method->klass->valuetype)
79 this_obj = (MonoObject *)mono_object_unbox (this_obj);
80 mono_runtime_invoke (method, this_obj, NULL, NULL);
83 /* The pseudo algorithm for type initialization from the spec
84 Note it doesn't say anything about domains - only threads.
86 2. If the type is initialized you are done.
87 2.1. If the type is not yet initialized, try to take an
89 2.2. If successful, record this thread as responsible for
90 initializing the type and proceed to step 2.3.
91 2.2.1. If not, see whether this thread or any thread
92 waiting for this thread to complete already holds the lock.
93 2.2.2. If so, return since blocking would create a deadlock. This thread
94 will now see an incompletely initialized state for the type,
95 but no deadlock will arise.
96 2.2.3 If not, block until the type is initialized then return.
97 2.3 Initialize the parent type and then all interfaces implemented
99 2.4 Execute the type initialization code for this type.
100 2.5 Mark the type as initialized, release the initialization lock,
101 awaken any threads waiting for this type to be initialized,
108 MonoNativeThreadId initializing_tid;
109 guint32 waiting_count;
111 MonoCoopMutex initialization_section;
112 } TypeInitializationLock;
114 /* for locking access to type_initialization_hash and blocked_thread_hash */
115 static MonoCoopMutex type_initialization_section;
118 mono_type_initialization_lock (void)
120 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
121 mono_coop_mutex_lock (&type_initialization_section);
125 mono_type_initialization_unlock (void)
127 mono_coop_mutex_unlock (&type_initialization_section);
131 mono_type_init_lock (TypeInitializationLock *lock)
133 MONO_REQ_GC_NEUTRAL_MODE;
135 mono_coop_mutex_lock (&lock->initialization_section);
139 mono_type_init_unlock (TypeInitializationLock *lock)
141 mono_coop_mutex_unlock (&lock->initialization_section);
144 /* from vtable to lock */
145 static GHashTable *type_initialization_hash;
147 /* from thread id to thread id being waited on */
148 static GHashTable *blocked_thread_hash;
151 static MonoThread *main_thread;
153 /* Functions supplied by the runtime */
154 static MonoRuntimeCallbacks callbacks;
157 * mono_thread_set_main:
158 * @thread: thread to set as the main thread
160 * This function can be used to instruct the runtime to treat @thread
161 * as the main thread, ie, the thread that would normally execute the Main()
162 * method. This basically means that at the end of @thread, the runtime will
163 * wait for the existing foreground threads to quit and other such details.
166 mono_thread_set_main (MonoThread *thread)
168 MONO_REQ_GC_UNSAFE_MODE;
170 static gboolean registered = FALSE;
173 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
177 main_thread = thread;
181 mono_thread_get_main (void)
183 MONO_REQ_GC_UNSAFE_MODE;
189 mono_type_initialization_init (void)
191 mono_coop_mutex_init_recursive (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 mono_os_mutex_init_recursive (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 mono_coop_mutex_destroy (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 mono_os_mutex_destroy (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MONO_REQ_GC_UNSAFE_MODE;
225 MonoDomain *domain = vtable->domain;
226 MonoClass *klass = vtable->klass;
230 if (!vtable->init_failed)
231 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
234 * If the initializing thread was rudely aborted, the exception is not stored
238 mono_domain_lock (domain);
239 if (domain->type_init_exception_hash)
240 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
241 mono_domain_unlock (domain);
244 if (klass->name_space && *klass->name_space)
245 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
247 full_name = g_strdup (klass->name);
248 ex = mono_get_exception_type_initialization (full_name, NULL);
255 * mono_runtime_class_init:
256 * @vtable: vtable that needs to be initialized
258 * This routine calls the class constructor for @vtable.
261 mono_runtime_class_init (MonoVTable *vtable)
263 MONO_REQ_GC_UNSAFE_MODE;
265 mono_runtime_class_init_full (vtable, TRUE);
269 * mono_runtime_class_init_full:
270 * @vtable that neeeds to be initialized
271 * @raise_exception is TRUE, exceptions are raised intead of returned
275 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
277 MONO_REQ_GC_UNSAFE_MODE;
280 MonoException *exc_to_throw;
281 MonoMethod *method = NULL;
284 MonoDomain *domain = vtable->domain;
285 TypeInitializationLock *lock;
286 MonoNativeThreadId tid;
287 int do_initialization = 0;
288 MonoDomain *last_domain = NULL;
290 if (vtable->initialized)
294 klass = vtable->klass;
296 if (!klass->image->checked_module_cctor) {
297 mono_image_check_for_module_cctor (klass->image);
298 if (klass->image->has_module_cctor) {
300 MonoClass *module_klass;
301 MonoVTable *module_vtable;
303 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
305 exc = mono_error_convert_to_exception (&error);
307 mono_raise_exception (exc);
311 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
314 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
319 method = mono_class_get_cctor (klass);
321 vtable->initialized = 1;
325 tid = mono_native_thread_id_get ();
327 mono_type_initialization_lock ();
328 /* double check... */
329 if (vtable->initialized) {
330 mono_type_initialization_unlock ();
333 if (vtable->init_failed) {
334 mono_type_initialization_unlock ();
336 /* The type initialization already failed once, rethrow the same exception */
338 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
339 return get_type_init_exception_for_vtable (vtable);
341 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
343 /* This thread will get to do the initialization */
344 if (mono_domain_get () != domain) {
345 /* Transfer into the target domain */
346 last_domain = mono_domain_get ();
347 if (!mono_domain_set (domain, FALSE)) {
348 vtable->initialized = 1;
349 mono_type_initialization_unlock ();
351 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
352 return mono_get_exception_appdomain_unloaded ();
355 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
356 mono_coop_mutex_init_recursive (&lock->initialization_section);
357 lock->initializing_tid = tid;
358 lock->waiting_count = 1;
360 /* grab the vtable lock while this thread still owns type_initialization_section */
361 /* This is why type_initialization_lock needs to enter blocking mode */
362 mono_type_init_lock (lock);
363 g_hash_table_insert (type_initialization_hash, vtable, lock);
364 do_initialization = 1;
367 TypeInitializationLock *pending_lock;
369 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
370 mono_type_initialization_unlock ();
373 /* see if the thread doing the initialization is already blocked on this thread */
374 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
375 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
376 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
377 if (!pending_lock->done) {
378 mono_type_initialization_unlock ();
381 /* the thread doing the initialization is blocked on this thread,
382 but on a lock that has already been freed. It just hasn't got
387 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
389 ++lock->waiting_count;
390 /* record the fact that we are waiting on the initializing thread */
391 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
393 mono_type_initialization_unlock ();
395 if (do_initialization) {
396 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
398 /* If the initialization failed, mark the class as unusable. */
399 /* Avoid infinite loops */
401 (klass->image == mono_defaults.corlib &&
402 !strcmp (klass->name_space, "System") &&
403 !strcmp (klass->name, "TypeInitializationException")))) {
404 vtable->init_failed = 1;
406 if (klass->name_space && *klass->name_space)
407 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
409 full_name = g_strdup (klass->name);
410 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
414 * Store the exception object so it could be thrown on subsequent
417 mono_domain_lock (domain);
418 if (!domain->type_init_exception_hash)
419 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
420 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
421 mono_domain_unlock (domain);
425 mono_domain_set (last_domain, TRUE);
427 mono_type_init_unlock (lock);
429 /* this just blocks until the initializing thread is done */
430 mono_type_init_lock (lock);
431 mono_type_init_unlock (lock);
434 mono_type_initialization_lock ();
435 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
436 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
437 --lock->waiting_count;
438 if (lock->waiting_count == 0) {
439 mono_coop_mutex_destroy (&lock->initialization_section);
440 g_hash_table_remove (type_initialization_hash, vtable);
443 mono_memory_barrier ();
444 if (!vtable->init_failed)
445 vtable->initialized = 1;
446 mono_type_initialization_unlock ();
448 if (vtable->init_failed) {
449 /* Either we were the initializing thread or we waited for the initialization */
451 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
452 return get_type_init_exception_for_vtable (vtable);
458 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
460 MONO_REQ_GC_NEUTRAL_MODE;
462 MonoVTable *vtable = (MonoVTable*)key;
464 TypeInitializationLock *lock = (TypeInitializationLock*) value;
465 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
468 * Have to set this since it cannot be set by the normal code in
469 * mono_runtime_class_init (). In this case, the exception object is not stored,
470 * and get_type_init_exception_for_class () needs to be aware of this.
472 vtable->init_failed = 1;
473 mono_type_init_unlock (lock);
474 --lock->waiting_count;
475 if (lock->waiting_count == 0) {
476 mono_coop_mutex_destroy (&lock->initialization_section);
485 mono_release_type_locks (MonoInternalThread *thread)
487 MONO_REQ_GC_UNSAFE_MODE;
489 mono_type_initialization_lock ();
490 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
491 mono_type_initialization_unlock ();
495 default_trampoline (MonoMethod *method)
501 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
503 g_assert_not_reached ();
508 #ifndef DISABLE_REMOTING
511 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
513 g_error ("remoting not installed");
517 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
521 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
523 g_assert_not_reached ();
527 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
528 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
529 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
530 static MonoImtThunkBuilder imt_thunk_builder;
531 static gboolean always_build_imt_thunks;
533 #if (MONO_IMT_SIZE > 32)
534 #error "MONO_IMT_SIZE cannot be larger than 32"
538 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
540 memcpy (&callbacks, cbs, sizeof (*cbs));
543 MonoRuntimeCallbacks*
544 mono_get_runtime_callbacks (void)
550 mono_install_trampoline (MonoTrampoline func)
552 arch_create_jit_trampoline = func? func: default_trampoline;
556 mono_install_jump_trampoline (MonoJumpTrampoline func)
558 arch_create_jump_trampoline = func? func: default_jump_trampoline;
561 #ifndef DISABLE_REMOTING
563 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
565 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
570 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
572 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
576 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
577 imt_thunk_builder = func;
581 mono_set_always_build_imt_thunks (gboolean value)
583 always_build_imt_thunks = value;
586 static MonoCompileFunc default_mono_compile_method = NULL;
589 * mono_install_compile_method:
590 * @func: function to install
592 * This is a VM internal routine
595 mono_install_compile_method (MonoCompileFunc func)
597 default_mono_compile_method = func;
601 * mono_compile_method:
602 * @method: The method to compile.
604 * This JIT-compiles the method, and returns the pointer to the native code
608 mono_compile_method (MonoMethod *method)
610 MONO_REQ_GC_NEUTRAL_MODE
612 if (!default_mono_compile_method) {
613 g_error ("compile method called on uninitialized runtime");
616 return default_mono_compile_method (method);
620 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
622 MONO_REQ_GC_NEUTRAL_MODE
624 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
628 mono_runtime_create_delegate_trampoline (MonoClass *klass)
630 MONO_REQ_GC_NEUTRAL_MODE
632 return arch_create_delegate_trampoline (mono_domain_get (), klass);
635 static MonoFreeMethodFunc default_mono_free_method = NULL;
638 * mono_install_free_method:
639 * @func: pointer to the MonoFreeMethodFunc used to release a method
641 * This is an internal VM routine, it is used for the engines to
642 * register a handler to release the resources associated with a method.
644 * Methods are freed when no more references to the delegate that holds
648 mono_install_free_method (MonoFreeMethodFunc func)
650 default_mono_free_method = func;
654 * mono_runtime_free_method:
655 * @domain; domain where the method is hosted
656 * @method: method to release
658 * This routine is invoked to free the resources associated with
659 * a method that has been JIT compiled. This is used to discard
660 * methods that were used only temporarily (for example, used in marshalling)
664 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
666 MONO_REQ_GC_NEUTRAL_MODE
668 if (default_mono_free_method != NULL)
669 default_mono_free_method (domain, method);
671 mono_method_clear_object (domain, method);
673 mono_free_method (method);
677 * The vtables in the root appdomain are assumed to be reachable by other
678 * roots, and we don't use typed allocation in the other domains.
681 /* The sync block is no longer a GC pointer */
682 #define GC_HEADER_BITMAP (0)
684 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
687 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
689 MONO_REQ_GC_NEUTRAL_MODE;
691 MonoClassField *field;
697 max_size = mono_class_data_size (klass) / sizeof (gpointer);
699 max_size = klass->instance_size / sizeof (gpointer);
700 if (max_size > size) {
701 g_assert (offset <= 0);
702 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
707 /*An Ephemeron cannot be marked by sgen*/
708 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
710 memset (bitmap, 0, size / 8);
715 for (p = klass; p != NULL; p = p->parent) {
716 gpointer iter = NULL;
717 while ((field = mono_class_get_fields (p, &iter))) {
721 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
723 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
726 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
729 /* FIXME: should not happen, flag as type load error */
730 if (field->type->byref)
733 if (static_fields && field->offset == -1)
737 pos = field->offset / sizeof (gpointer);
740 type = mono_type_get_underlying_type (field->type);
741 switch (type->type) {
744 case MONO_TYPE_FNPTR:
746 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
751 if (klass->image != mono_defaults.corlib)
754 case MONO_TYPE_STRING:
755 case MONO_TYPE_SZARRAY:
756 case MONO_TYPE_CLASS:
757 case MONO_TYPE_OBJECT:
758 case MONO_TYPE_ARRAY:
759 g_assert ((field->offset % sizeof(gpointer)) == 0);
761 g_assert (pos < size || pos <= max_size);
762 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
763 *max_set = MAX (*max_set, pos);
765 case MONO_TYPE_GENERICINST:
766 if (!mono_type_generic_inst_is_valuetype (type)) {
767 g_assert ((field->offset % sizeof(gpointer)) == 0);
769 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
770 *max_set = MAX (*max_set, pos);
775 case MONO_TYPE_VALUETYPE: {
776 MonoClass *fclass = mono_class_from_mono_type (field->type);
777 if (fclass->has_references) {
778 /* remove the object header */
779 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
793 case MONO_TYPE_BOOLEAN:
797 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
808 * mono_class_compute_bitmap:
810 * Mono internal function to compute a bitmap of reference fields in a class.
813 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
815 MONO_REQ_GC_NEUTRAL_MODE;
817 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
822 * similar to the above, but sets the bits in the bitmap for any non-ref field
823 * and ignores static fields
826 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
828 MonoClassField *field;
833 max_size = class->instance_size / sizeof (gpointer);
834 if (max_size >= size) {
835 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
838 for (p = class; p != NULL; p = p->parent) {
839 gpointer iter = NULL;
840 while ((field = mono_class_get_fields (p, &iter))) {
843 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
845 /* FIXME: should not happen, flag as type load error */
846 if (field->type->byref)
849 pos = field->offset / sizeof (gpointer);
852 type = mono_type_get_underlying_type (field->type);
853 switch (type->type) {
854 #if SIZEOF_VOID_P == 8
858 case MONO_TYPE_FNPTR:
863 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
864 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
865 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
868 #if SIZEOF_VOID_P == 4
872 case MONO_TYPE_FNPTR:
877 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
878 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
879 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
885 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
886 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
887 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
890 case MONO_TYPE_BOOLEAN:
893 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
895 case MONO_TYPE_STRING:
896 case MONO_TYPE_SZARRAY:
897 case MONO_TYPE_CLASS:
898 case MONO_TYPE_OBJECT:
899 case MONO_TYPE_ARRAY:
901 case MONO_TYPE_GENERICINST:
902 if (!mono_type_generic_inst_is_valuetype (type)) {
907 case MONO_TYPE_VALUETYPE: {
908 MonoClass *fclass = mono_class_from_mono_type (field->type);
909 /* remove the object header */
910 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
914 g_assert_not_reached ();
923 * mono_class_insecure_overlapping:
924 * check if a class with explicit layout has references and non-references
925 * fields overlapping.
927 * Returns: TRUE if it is insecure to load the type.
930 mono_class_insecure_overlapping (MonoClass *klass)
934 gsize default_bitmap [4] = {0};
936 gsize default_nrbitmap [4] = {0};
937 int i, insecure = FALSE;
940 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
941 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
943 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
944 int idx = i % (sizeof (bitmap [0]) * 8);
945 if (bitmap [idx] & nrbitmap [idx]) {
950 if (bitmap != default_bitmap)
952 if (nrbitmap != default_nrbitmap)
955 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
963 mono_string_alloc (int length)
965 MONO_REQ_GC_UNSAFE_MODE;
968 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
969 mono_error_raise_exception (&error); /* FIXME don't raise here */
975 mono_class_compute_gc_descriptor (MonoClass *klass)
977 MONO_REQ_GC_NEUTRAL_MODE;
981 gsize default_bitmap [4] = {0};
982 static gboolean gcj_inited = FALSE;
987 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
988 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
991 mono_loader_unlock ();
995 mono_class_init (klass);
997 if (klass->gc_descr_inited)
1000 klass->gc_descr_inited = TRUE;
1001 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1003 bitmap = default_bitmap;
1004 if (klass == mono_defaults.string_class) {
1005 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1006 } else if (klass->rank) {
1007 mono_class_compute_gc_descriptor (klass->element_class);
1008 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1010 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1011 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1012 class->name_space, class->name);*/
1014 /* remove the object header */
1015 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1016 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));
1017 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1018 class->name_space, class->name);*/
1019 if (bitmap != default_bitmap)
1023 /*static int count = 0;
1026 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1027 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1029 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1030 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1032 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1033 if (bitmap != default_bitmap)
1039 * field_is_special_static:
1040 * @fklass: The MonoClass to look up.
1041 * @field: The MonoClassField describing the field.
1043 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1044 * SPECIAL_STATIC_NONE otherwise.
1047 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1049 MONO_REQ_GC_NEUTRAL_MODE;
1051 MonoCustomAttrInfo *ainfo;
1053 ainfo = mono_custom_attrs_from_field (fklass, field);
1056 for (i = 0; i < ainfo->num_attrs; ++i) {
1057 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1058 if (klass->image == mono_defaults.corlib) {
1059 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1060 mono_custom_attrs_free (ainfo);
1061 return SPECIAL_STATIC_THREAD;
1063 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1064 mono_custom_attrs_free (ainfo);
1065 return SPECIAL_STATIC_CONTEXT;
1069 mono_custom_attrs_free (ainfo);
1070 return SPECIAL_STATIC_NONE;
1073 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1074 #define mix(a,b,c) { \
1075 a -= c; a ^= rot(c, 4); c += b; \
1076 b -= a; b ^= rot(a, 6); a += c; \
1077 c -= b; c ^= rot(b, 8); b += a; \
1078 a -= c; a ^= rot(c,16); c += b; \
1079 b -= a; b ^= rot(a,19); a += c; \
1080 c -= b; c ^= rot(b, 4); b += a; \
1082 #define final(a,b,c) { \
1083 c ^= b; c -= rot(b,14); \
1084 a ^= c; a -= rot(c,11); \
1085 b ^= a; b -= rot(a,25); \
1086 c ^= b; c -= rot(b,16); \
1087 a ^= c; a -= rot(c,4); \
1088 b ^= a; b -= rot(a,14); \
1089 c ^= b; c -= rot(b,24); \
1093 * mono_method_get_imt_slot:
1095 * The IMT slot is embedded into AOTed code, so this must return the same value
1096 * for the same method across all executions. This means:
1097 * - pointers shouldn't be used as hash values.
1098 * - mono_metadata_str_hash () should be used for hashing strings.
1101 mono_method_get_imt_slot (MonoMethod *method)
1103 MONO_REQ_GC_NEUTRAL_MODE;
1105 MonoMethodSignature *sig;
1107 guint32 *hashes_start, *hashes;
1111 /* This can be used to stress tests the collision code */
1115 * We do this to simplify generic sharing. It will hurt
1116 * performance in cases where a class implements two different
1117 * instantiations of the same generic interface.
1118 * The code in build_imt_slots () depends on this.
1120 if (method->is_inflated)
1121 method = ((MonoMethodInflated*)method)->declaring;
1123 sig = mono_method_signature (method);
1124 hashes_count = sig->param_count + 4;
1125 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1126 hashes = hashes_start;
1128 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1129 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1130 method->klass->name_space, method->klass->name, method->name);
1133 /* Initialize hashes */
1134 hashes [0] = mono_metadata_str_hash (method->klass->name);
1135 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1136 hashes [2] = mono_metadata_str_hash (method->name);
1137 hashes [3] = mono_metadata_type_hash (sig->ret);
1138 for (i = 0; i < sig->param_count; i++) {
1139 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1142 /* Setup internal state */
1143 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1145 /* Handle most of the hashes */
1146 while (hashes_count > 3) {
1155 /* Handle the last 3 hashes (all the case statements fall through) */
1156 switch (hashes_count) {
1157 case 3 : c += hashes [2];
1158 case 2 : b += hashes [1];
1159 case 1 : a += hashes [0];
1161 case 0: /* nothing left to add */
1165 free (hashes_start);
1166 /* Report the result */
1167 return c % MONO_IMT_SIZE;
1176 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1177 MONO_REQ_GC_NEUTRAL_MODE;
1179 guint32 imt_slot = mono_method_get_imt_slot (method);
1180 MonoImtBuilderEntry *entry;
1182 if (slot_num >= 0 && imt_slot != slot_num) {
1183 /* we build just a single imt slot and this is not it */
1187 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1188 entry->key = method;
1189 entry->value.vtable_slot = vtable_slot;
1190 entry->next = imt_builder [imt_slot];
1191 if (imt_builder [imt_slot] != NULL) {
1192 entry->children = imt_builder [imt_slot]->children + 1;
1193 if (entry->children == 1) {
1194 mono_stats.imt_slots_with_collisions++;
1195 *imt_collisions_bitmap |= (1 << imt_slot);
1198 entry->children = 0;
1199 mono_stats.imt_used_slots++;
1201 imt_builder [imt_slot] = entry;
1204 char *method_name = mono_method_full_name (method, TRUE);
1205 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1206 method, method_name, imt_slot, vtable_slot, entry->children);
1207 g_free (method_name);
1214 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1216 MonoMethod *method = e->key;
1217 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1221 method->klass->name_space,
1222 method->klass->name,
1225 printf (" * %s: NULL\n", message);
1231 compare_imt_builder_entries (const void *p1, const void *p2) {
1232 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1233 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1235 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1239 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1241 MONO_REQ_GC_NEUTRAL_MODE;
1243 int count = end - start;
1244 int chunk_start = out_array->len;
1247 for (i = start; i < end; ++i) {
1248 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1249 item->key = sorted_array [i]->key;
1250 item->value = sorted_array [i]->value;
1251 item->has_target_code = sorted_array [i]->has_target_code;
1252 item->is_equals = TRUE;
1254 item->check_target_idx = out_array->len + 1;
1256 item->check_target_idx = 0;
1257 g_ptr_array_add (out_array, item);
1260 int middle = start + count / 2;
1261 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1263 item->key = sorted_array [middle]->key;
1264 item->is_equals = FALSE;
1265 g_ptr_array_add (out_array, item);
1266 imt_emit_ir (sorted_array, start, middle, out_array);
1267 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1273 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1274 MONO_REQ_GC_NEUTRAL_MODE;
1276 int number_of_entries = entries->children + 1;
1277 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1278 GPtrArray *result = g_ptr_array_new ();
1279 MonoImtBuilderEntry *current_entry;
1282 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1283 sorted_array [i] = current_entry;
1285 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1287 /*for (i = 0; i < number_of_entries; i++) {
1288 print_imt_entry (" sorted array:", sorted_array [i], i);
1291 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1293 free (sorted_array);
1298 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1300 MONO_REQ_GC_NEUTRAL_MODE;
1302 if (imt_builder_entry != NULL) {
1303 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1304 /* No collision, return the vtable slot contents */
1305 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1307 /* Collision, build the thunk */
1308 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1311 result = imt_thunk_builder (vtable, domain,
1312 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1313 for (i = 0; i < imt_ir->len; ++i)
1314 g_free (g_ptr_array_index (imt_ir, i));
1315 g_ptr_array_free (imt_ir, TRUE);
1327 static MonoImtBuilderEntry*
1328 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1331 * LOCKING: requires the loader and domain locks.
1335 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1337 MONO_REQ_GC_NEUTRAL_MODE;
1341 guint32 imt_collisions_bitmap = 0;
1342 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1343 int method_count = 0;
1344 gboolean record_method_count_for_max_collisions = FALSE;
1345 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1348 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1350 for (i = 0; i < klass->interface_offsets_count; ++i) {
1351 MonoClass *iface = klass->interfaces_packed [i];
1352 int interface_offset = klass->interface_offsets_packed [i];
1353 int method_slot_in_interface, vt_slot;
1355 if (mono_class_has_variant_generic_params (iface))
1356 has_variant_iface = TRUE;
1358 mono_class_setup_methods (iface);
1359 vt_slot = interface_offset;
1360 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1363 if (slot_num >= 0 && iface->is_inflated) {
1365 * The imt slot of the method is the same as for its declaring method,
1366 * see the comment in mono_method_get_imt_slot (), so we can
1367 * avoid inflating methods which will be discarded by
1368 * add_imt_builder_entry anyway.
1370 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1371 if (mono_method_get_imt_slot (method) != slot_num) {
1376 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1377 if (method->is_generic) {
1378 has_generic_virtual = TRUE;
1383 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1384 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1389 if (extra_interfaces) {
1390 int interface_offset = klass->vtable_size;
1392 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1393 MonoClass* iface = (MonoClass *)list_item->data;
1394 int method_slot_in_interface;
1395 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1396 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1398 if (method->is_generic)
1399 has_generic_virtual = TRUE;
1400 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1402 interface_offset += iface->method.count;
1405 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1406 /* overwrite the imt slot only if we're building all the entries or if
1407 * we're building this specific one
1409 if (slot_num < 0 || i == slot_num) {
1410 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1413 if (imt_builder [i]) {
1414 MonoImtBuilderEntry *entry;
1416 /* Link entries with imt_builder [i] */
1417 for (entry = entries; entry->next; entry = entry->next) {
1419 MonoMethod *method = (MonoMethod*)entry->key;
1420 char *method_name = mono_method_full_name (method, TRUE);
1421 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1422 g_free (method_name);
1425 entry->next = imt_builder [i];
1426 entries->children += imt_builder [i]->children + 1;
1428 imt_builder [i] = entries;
1431 if (has_generic_virtual || has_variant_iface) {
1433 * There might be collisions later when the the thunk is expanded.
1435 imt_collisions_bitmap |= (1 << i);
1438 * The IMT thunk might be called with an instance of one of the
1439 * generic virtual methods, so has to fallback to the IMT trampoline.
1441 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1443 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1446 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1450 if (imt_builder [i] != NULL) {
1451 int methods_in_slot = imt_builder [i]->children + 1;
1452 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1453 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1454 record_method_count_for_max_collisions = TRUE;
1456 method_count += methods_in_slot;
1460 mono_stats.imt_number_of_methods += method_count;
1461 if (record_method_count_for_max_collisions) {
1462 mono_stats.imt_method_count_when_max_collisions = method_count;
1465 for (i = 0; i < MONO_IMT_SIZE; i++) {
1466 MonoImtBuilderEntry* entry = imt_builder [i];
1467 while (entry != NULL) {
1468 MonoImtBuilderEntry* next = entry->next;
1474 /* we OR the bitmap since we may build just a single imt slot at a time */
1475 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1479 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1480 MONO_REQ_GC_NEUTRAL_MODE;
1482 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1486 * mono_vtable_build_imt_slot:
1487 * @vtable: virtual object table struct
1488 * @imt_slot: slot in the IMT table
1490 * Fill the given @imt_slot in the IMT table of @vtable with
1491 * a trampoline or a thunk for the case of collisions.
1492 * This is part of the internal mono API.
1494 * LOCKING: Take the domain lock.
1497 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1499 MONO_REQ_GC_NEUTRAL_MODE;
1501 gpointer *imt = (gpointer*)vtable;
1502 imt -= MONO_IMT_SIZE;
1503 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1505 /* no support for extra interfaces: the proxy objects will need
1506 * to build the complete IMT
1507 * Update and heck needs to ahppen inside the proper domain lock, as all
1508 * the changes made to a MonoVTable.
1510 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1511 mono_domain_lock (vtable->domain);
1512 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1513 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1514 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1515 mono_domain_unlock (vtable->domain);
1516 mono_loader_unlock ();
1521 * The first two free list entries both belong to the wait list: The
1522 * first entry is the pointer to the head of the list and the second
1523 * entry points to the last element. That way appending and removing
1524 * the first element are both O(1) operations.
1526 #ifdef MONO_SMALL_CONFIG
1527 #define NUM_FREE_LISTS 6
1529 #define NUM_FREE_LISTS 12
1531 #define FIRST_FREE_LIST_SIZE 64
1532 #define MAX_WAIT_LENGTH 50
1533 #define THUNK_THRESHOLD 10
1536 * LOCKING: The domain lock must be held.
1539 init_thunk_free_lists (MonoDomain *domain)
1541 MONO_REQ_GC_NEUTRAL_MODE;
1543 if (domain->thunk_free_lists)
1545 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1549 list_index_for_size (int item_size)
1552 int size = FIRST_FREE_LIST_SIZE;
1554 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1563 * mono_method_alloc_generic_virtual_thunk:
1565 * @size: size in bytes
1567 * Allocs size bytes to be used for the code of a generic virtual
1568 * thunk. It's either allocated from the domain's code manager or
1569 * reused from a previously invalidated piece.
1571 * LOCKING: The domain lock must be held.
1574 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1576 MONO_REQ_GC_NEUTRAL_MODE;
1578 static gboolean inited = FALSE;
1579 static int generic_virtual_thunks_size = 0;
1583 MonoThunkFreeList **l;
1585 init_thunk_free_lists (domain);
1587 size += sizeof (guint32);
1588 if (size < sizeof (MonoThunkFreeList))
1589 size = sizeof (MonoThunkFreeList);
1591 i = list_index_for_size (size);
1592 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1593 if ((*l)->size >= size) {
1594 MonoThunkFreeList *item = *l;
1596 return ((guint32*)item) + 1;
1600 /* no suitable item found - search lists of larger sizes */
1601 while (++i < NUM_FREE_LISTS) {
1602 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1605 g_assert (item->size > size);
1606 domain->thunk_free_lists [i] = item->next;
1607 return ((guint32*)item) + 1;
1610 /* still nothing found - allocate it */
1612 mono_counters_register ("Generic virtual thunk bytes",
1613 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1616 generic_virtual_thunks_size += size;
1618 p = (guint32 *)mono_domain_code_reserve (domain, size);
1621 mono_domain_lock (domain);
1622 if (!domain->generic_virtual_thunks)
1623 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1624 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1625 mono_domain_unlock (domain);
1631 * LOCKING: The domain lock must be held.
1634 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1636 MONO_REQ_GC_NEUTRAL_MODE;
1638 guint32 *p = (guint32 *)code;
1639 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1640 gboolean found = FALSE;
1642 mono_domain_lock (domain);
1643 if (!domain->generic_virtual_thunks)
1644 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1645 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1647 mono_domain_unlock (domain);
1650 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1652 init_thunk_free_lists (domain);
1654 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1655 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1656 int length = item->length;
1659 /* unlink the first item from the wait list */
1660 domain->thunk_free_lists [0] = item->next;
1661 domain->thunk_free_lists [0]->length = length - 1;
1663 i = list_index_for_size (item->size);
1665 /* put it in the free list */
1666 item->next = domain->thunk_free_lists [i];
1667 domain->thunk_free_lists [i] = item;
1671 if (domain->thunk_free_lists [1]) {
1672 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1673 domain->thunk_free_lists [0]->length++;
1675 g_assert (!domain->thunk_free_lists [0]);
1677 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1678 domain->thunk_free_lists [0]->length = 1;
1682 typedef struct _GenericVirtualCase {
1686 struct _GenericVirtualCase *next;
1687 } GenericVirtualCase;
1690 * get_generic_virtual_entries:
1692 * Return IMT entries for the generic virtual method instances and
1693 * variant interface methods for vtable slot
1696 static MonoImtBuilderEntry*
1697 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1699 MONO_REQ_GC_NEUTRAL_MODE;
1701 GenericVirtualCase *list;
1702 MonoImtBuilderEntry *entries;
1704 mono_domain_lock (domain);
1705 if (!domain->generic_virtual_cases)
1706 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1708 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1711 for (; list; list = list->next) {
1712 MonoImtBuilderEntry *entry;
1714 if (list->count < THUNK_THRESHOLD)
1717 entry = g_new0 (MonoImtBuilderEntry, 1);
1718 entry->key = list->method;
1719 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1720 entry->has_target_code = 1;
1722 entry->children = entries->children + 1;
1723 entry->next = entries;
1727 mono_domain_unlock (domain);
1729 /* FIXME: Leaking memory ? */
1734 * mono_method_add_generic_virtual_invocation:
1736 * @vtable_slot: pointer to the vtable slot
1737 * @method: the inflated generic virtual method
1738 * @code: the method's code
1740 * Registers a call via unmanaged code to a generic virtual method
1741 * instantiation or variant interface method. If the number of calls reaches a threshold
1742 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1743 * virtual method thunk.
1746 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1747 gpointer *vtable_slot,
1748 MonoMethod *method, gpointer code)
1750 MONO_REQ_GC_NEUTRAL_MODE;
1752 static gboolean inited = FALSE;
1753 static int num_added = 0;
1755 GenericVirtualCase *gvc, *list;
1756 MonoImtBuilderEntry *entries;
1760 mono_domain_lock (domain);
1761 if (!domain->generic_virtual_cases)
1762 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1764 /* Check whether the case was already added */
1765 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1768 if (gvc->method == method)
1773 /* If not found, make a new one */
1775 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1776 gvc->method = method;
1779 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1781 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1784 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1790 if (++gvc->count == THUNK_THRESHOLD) {
1791 gpointer *old_thunk = (void **)*vtable_slot;
1792 gpointer vtable_trampoline = NULL;
1793 gpointer imt_trampoline = NULL;
1795 if ((gpointer)vtable_slot < (gpointer)vtable) {
1796 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1797 int imt_slot = MONO_IMT_SIZE + displacement;
1799 /* Force the rebuild of the thunk at the next call */
1800 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1801 *vtable_slot = imt_trampoline;
1803 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1805 entries = get_generic_virtual_entries (domain, vtable_slot);
1807 sorted = imt_sort_slot_entries (entries);
1809 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1813 MonoImtBuilderEntry *next = entries->next;
1818 for (i = 0; i < sorted->len; ++i)
1819 g_free (g_ptr_array_index (sorted, i));
1820 g_ptr_array_free (sorted, TRUE);
1823 #ifndef __native_client__
1824 /* We don't re-use any thunks as there is a lot of overhead */
1825 /* to deleting and re-using code in Native Client. */
1826 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1827 invalidate_generic_virtual_thunk (domain, old_thunk);
1831 mono_domain_unlock (domain);
1834 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1837 * mono_class_vtable:
1838 * @domain: the application domain
1839 * @class: the class to initialize
1841 * VTables are domain specific because we create domain specific code, and
1842 * they contain the domain specific static class data.
1843 * On failure, NULL is returned, and class->exception_type is set.
1846 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1848 return mono_class_vtable_full (domain, klass, FALSE);
1852 * mono_class_vtable_full:
1853 * @domain: the application domain
1854 * @class: the class to initialize
1855 * @raise_on_error if an exception should be raised on failure or not
1857 * VTables are domain specific because we create domain specific code, and
1858 * they contain the domain specific static class data.
1861 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1863 MONO_REQ_GC_UNSAFE_MODE;
1865 MonoClassRuntimeInfo *runtime_info;
1869 if (klass->exception_type) {
1871 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1875 /* this check can be inlined in jitted code, too */
1876 runtime_info = klass->runtime_info;
1877 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1878 return runtime_info->domain_vtables [domain->domain_id];
1879 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1883 * mono_class_try_get_vtable:
1884 * @domain: the application domain
1885 * @class: the class to initialize
1887 * This function tries to get the associated vtable from @class if
1888 * it was already created.
1891 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1893 MONO_REQ_GC_NEUTRAL_MODE;
1895 MonoClassRuntimeInfo *runtime_info;
1899 runtime_info = klass->runtime_info;
1900 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1901 return runtime_info->domain_vtables [domain->domain_id];
1906 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1908 MONO_REQ_GC_NEUTRAL_MODE;
1910 size_t alloc_offset;
1913 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1914 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1915 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1917 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1918 g_assert ((imt_table_bytes & 7) == 4);
1925 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1929 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1931 MONO_REQ_GC_UNSAFE_MODE;
1934 MonoClassRuntimeInfo *runtime_info, *old_info;
1935 MonoClassField *field;
1937 int i, vtable_slots;
1938 size_t imt_table_bytes;
1940 guint32 vtable_size, class_size;
1942 gpointer *interface_offsets;
1944 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1945 mono_domain_lock (domain);
1946 runtime_info = klass->runtime_info;
1947 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1948 mono_domain_unlock (domain);
1949 mono_loader_unlock ();
1950 return runtime_info->domain_vtables [domain->domain_id];
1952 if (!klass->inited || klass->exception_type) {
1953 if (!mono_class_init (klass) || klass->exception_type) {
1954 mono_domain_unlock (domain);
1955 mono_loader_unlock ();
1957 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1962 /* Array types require that their element type be valid*/
1963 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1964 MonoClass *element_class = klass->element_class;
1965 if (!element_class->inited)
1966 mono_class_init (element_class);
1968 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1969 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1970 mono_class_setup_vtable (element_class);
1972 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1973 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1974 if (klass->exception_type == MONO_EXCEPTION_NONE)
1975 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1976 mono_domain_unlock (domain);
1977 mono_loader_unlock ();
1979 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1985 * For some classes, mono_class_init () already computed klass->vtable_size, and
1986 * that is all that is needed because of the vtable trampolines.
1988 if (!klass->vtable_size)
1989 mono_class_setup_vtable (klass);
1991 if (klass->generic_class && !klass->vtable)
1992 mono_class_check_vtable_constraints (klass, NULL);
1994 /* Initialize klass->has_finalize */
1995 mono_class_has_finalizer (klass);
1997 if (klass->exception_type) {
1998 mono_domain_unlock (domain);
1999 mono_loader_unlock ();
2001 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2005 vtable_slots = klass->vtable_size;
2006 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2007 class_size = mono_class_data_size (klass);
2011 if (klass->interface_offsets_count) {
2012 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2013 mono_stats.imt_number_of_tables++;
2014 mono_stats.imt_tables_size += imt_table_bytes;
2016 imt_table_bytes = 0;
2019 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2021 mono_stats.used_class_count++;
2022 mono_stats.class_vtable_size += vtable_size;
2024 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2025 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2026 g_assert (!((gsize)vt & 7));
2029 vt->rank = klass->rank;
2030 vt->domain = domain;
2032 mono_class_compute_gc_descriptor (klass);
2034 * We can't use typed allocation in the non-root domains, since the
2035 * collector needs the GC descriptor stored in the vtable even after
2036 * the mempool containing the vtable is destroyed when the domain is
2037 * unloaded. An alternative might be to allocate vtables in the GC
2038 * heap, but this does not seem to work (it leads to crashes inside
2039 * libgc). If that approach is tried, two gc descriptors need to be
2040 * allocated for each class: one for the root domain, and one for all
2041 * other domains. The second descriptor should contain a bit for the
2042 * vtable field in MonoObject, since we can no longer assume the
2043 * vtable is reachable by other roots after the appdomain is unloaded.
2045 #ifdef HAVE_BOEHM_GC
2046 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2047 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2050 vt->gc_descr = klass->gc_descr;
2052 gc_bits = mono_gc_get_vtable_bits (klass);
2053 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2055 vt->gc_bits = gc_bits;
2058 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2059 if (klass->has_static_refs) {
2060 MonoGCDescriptor statics_gc_descr;
2062 gsize default_bitmap [4] = {0};
2065 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2066 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2067 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2068 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2069 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2070 if (bitmap != default_bitmap)
2073 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2075 vt->has_static_fields = TRUE;
2076 mono_stats.class_static_data_size += class_size;
2080 while ((field = mono_class_get_fields (klass, &iter))) {
2081 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2083 if (mono_field_is_deleted (field))
2085 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2086 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2087 if (special_static != SPECIAL_STATIC_NONE) {
2088 guint32 size, offset;
2090 gsize default_bitmap [4] = {0};
2095 if (mono_type_is_reference (field->type)) {
2096 default_bitmap [0] = 1;
2098 bitmap = default_bitmap;
2099 } else if (mono_type_is_struct (field->type)) {
2100 fclass = mono_class_from_mono_type (field->type);
2101 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2102 numbits = max_set + 1;
2104 default_bitmap [0] = 0;
2106 bitmap = default_bitmap;
2108 size = mono_type_size (field->type, &align);
2109 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2110 if (!domain->special_static_fields)
2111 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2112 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2113 if (bitmap != default_bitmap)
2116 * This marks the field as special static to speed up the
2117 * checks in mono_field_static_get/set_value ().
2123 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2124 MonoClass *fklass = mono_class_from_mono_type (field->type);
2125 const char *data = mono_field_get_data (field);
2127 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2128 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2129 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2132 if (fklass->valuetype) {
2133 memcpy (t, data, mono_class_value_size (fklass, NULL));
2135 /* it's a pointer type: add check */
2136 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2143 vt->max_interface_id = klass->max_interface_id;
2144 vt->interface_bitmap = klass->interface_bitmap;
2146 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2147 // class->name, klass->interface_offsets_count);
2149 /* Initialize vtable */
2150 if (callbacks.get_vtable_trampoline) {
2151 // This also covers the AOT case
2152 for (i = 0; i < klass->vtable_size; ++i) {
2153 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2156 mono_class_setup_vtable (klass);
2158 for (i = 0; i < klass->vtable_size; ++i) {
2161 if ((cm = klass->vtable [i]))
2162 vt->vtable [i] = arch_create_jit_trampoline (cm);
2166 if (imt_table_bytes) {
2167 /* Now that the vtable is full, we can actually fill up the IMT */
2168 for (i = 0; i < MONO_IMT_SIZE; ++i)
2169 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2173 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2174 * re-acquire them and check if another thread has created the vtable in the meantime.
2176 /* Special case System.MonoType to avoid infinite recursion */
2177 if (klass != mono_defaults.monotype_class) {
2178 /*FIXME check for OOM*/
2179 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2180 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2181 /* This is unregistered in
2182 unregister_vtable_reflection_type() in
2184 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2187 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2189 /* class_vtable_array keeps an array of created vtables
2191 g_ptr_array_add (domain->class_vtable_array, vt);
2192 /* klass->runtime_info is protected by the loader lock, both when
2193 * it it enlarged and when it is stored info.
2197 * Store the vtable in klass->runtime_info.
2198 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2200 mono_memory_barrier ();
2202 old_info = klass->runtime_info;
2203 if (old_info && old_info->max_domain >= domain->domain_id) {
2204 /* someone already created a large enough runtime info */
2205 old_info->domain_vtables [domain->domain_id] = vt;
2207 int new_size = domain->domain_id;
2209 new_size = MAX (new_size, old_info->max_domain);
2211 /* make the new size a power of two */
2213 while (new_size > i)
2216 /* this is a bounded memory retention issue: may want to
2217 * handle it differently when we'll have a rcu-like system.
2219 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2220 runtime_info->max_domain = new_size - 1;
2221 /* copy the stuff from the older info */
2223 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2225 runtime_info->domain_vtables [domain->domain_id] = vt;
2227 mono_memory_barrier ();
2228 klass->runtime_info = runtime_info;
2231 if (klass == mono_defaults.monotype_class) {
2232 /*FIXME check for OOM*/
2233 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2234 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2235 /* This is unregistered in
2236 unregister_vtable_reflection_type() in
2238 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2241 mono_domain_unlock (domain);
2242 mono_loader_unlock ();
2244 /* make sure the parent is initialized */
2245 /*FIXME shouldn't this fail the current type?*/
2247 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2252 #ifndef DISABLE_REMOTING
2254 * mono_class_proxy_vtable:
2255 * @domain: the application domain
2256 * @remove_class: the remote class
2258 * Creates a vtable for transparent proxies. It is basically
2259 * a copy of the real vtable of the class wrapped in @remote_class,
2260 * but all function pointers invoke the remoting functions, and
2261 * vtable->klass points to the transparent proxy class, and not to @class.
2264 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2266 MONO_REQ_GC_UNSAFE_MODE;
2269 MonoVTable *vt, *pvt;
2270 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2272 GSList *extra_interfaces = NULL;
2273 MonoClass *klass = remote_class->proxy_class;
2274 gpointer *interface_offsets;
2277 size_t imt_table_bytes;
2279 #ifdef COMPRESSED_INTERFACE_BITMAP
2283 vt = mono_class_vtable (domain, klass);
2284 g_assert (vt); /*FIXME property handle failure*/
2285 max_interface_id = vt->max_interface_id;
2287 /* Calculate vtable space for extra interfaces */
2288 for (j = 0; j < remote_class->interface_count; j++) {
2289 MonoClass* iclass = remote_class->interfaces[j];
2293 /*FIXME test for interfaces with variant generic arguments*/
2294 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2295 continue; /* interface implemented by the class */
2296 if (g_slist_find (extra_interfaces, iclass))
2299 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2301 method_count = mono_class_num_methods (iclass);
2303 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2304 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2306 for (i = 0; i < ifaces->len; ++i) {
2307 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2308 /*FIXME test for interfaces with variant generic arguments*/
2309 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2310 continue; /* interface implemented by the class */
2311 if (g_slist_find (extra_interfaces, ic))
2313 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2314 method_count += mono_class_num_methods (ic);
2316 g_ptr_array_free (ifaces, TRUE);
2319 extra_interface_vtsize += method_count * sizeof (gpointer);
2320 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2323 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2324 mono_stats.imt_number_of_tables++;
2325 mono_stats.imt_tables_size += imt_table_bytes;
2327 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2329 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2331 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2332 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2333 g_assert (!((gsize)pvt & 7));
2335 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2337 pvt->klass = mono_defaults.transparent_proxy_class;
2338 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2339 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2341 /* initialize vtable */
2342 mono_class_setup_vtable (klass);
2343 for (i = 0; i < klass->vtable_size; ++i) {
2346 if ((cm = klass->vtable [i]))
2347 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2349 pvt->vtable [i] = NULL;
2352 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2353 /* create trampolines for abstract methods */
2354 for (k = klass; k; k = k->parent) {
2356 gpointer iter = NULL;
2357 while ((m = mono_class_get_methods (k, &iter)))
2358 if (!pvt->vtable [m->slot])
2359 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2363 pvt->max_interface_id = max_interface_id;
2364 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2365 #ifdef COMPRESSED_INTERFACE_BITMAP
2366 bitmap = (uint8_t *)g_malloc0 (bsize);
2368 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2371 for (i = 0; i < klass->interface_offsets_count; ++i) {
2372 int interface_id = klass->interfaces_packed [i]->interface_id;
2373 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2376 if (extra_interfaces) {
2377 int slot = klass->vtable_size;
2383 /* Create trampolines for the methods of the interfaces */
2384 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2385 interf = (MonoClass *)list_item->data;
2387 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2391 while ((cm = mono_class_get_methods (interf, &iter)))
2392 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2394 slot += mono_class_num_methods (interf);
2398 /* Now that the vtable is full, we can actually fill up the IMT */
2399 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2400 if (extra_interfaces) {
2401 g_slist_free (extra_interfaces);
2404 #ifdef COMPRESSED_INTERFACE_BITMAP
2405 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2406 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2407 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2410 pvt->interface_bitmap = bitmap;
2415 #endif /* DISABLE_REMOTING */
2418 * mono_class_field_is_special_static:
2420 * Returns whether @field is a thread/context static field.
2423 mono_class_field_is_special_static (MonoClassField *field)
2425 MONO_REQ_GC_NEUTRAL_MODE
2427 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2429 if (mono_field_is_deleted (field))
2431 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2432 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2439 * mono_class_field_get_special_static_type:
2440 * @field: The MonoClassField describing the field.
2442 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2443 * SPECIAL_STATIC_NONE otherwise.
2446 mono_class_field_get_special_static_type (MonoClassField *field)
2448 MONO_REQ_GC_NEUTRAL_MODE
2450 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2451 return SPECIAL_STATIC_NONE;
2452 if (mono_field_is_deleted (field))
2453 return SPECIAL_STATIC_NONE;
2454 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2455 return field_is_special_static (field->parent, field);
2456 return SPECIAL_STATIC_NONE;
2460 * mono_class_has_special_static_fields:
2462 * Returns whenever @klass has any thread/context static fields.
2465 mono_class_has_special_static_fields (MonoClass *klass)
2467 MONO_REQ_GC_NEUTRAL_MODE
2469 MonoClassField *field;
2473 while ((field = mono_class_get_fields (klass, &iter))) {
2474 g_assert (field->parent == klass);
2475 if (mono_class_field_is_special_static (field))
2482 #ifndef DISABLE_REMOTING
2484 * create_remote_class_key:
2485 * Creates an array of pointers that can be used as a hash key for a remote class.
2486 * The first element of the array is the number of pointers.
2489 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2491 MONO_REQ_GC_NEUTRAL_MODE;
2496 if (remote_class == NULL) {
2497 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2498 key = (void **)g_malloc (sizeof(gpointer) * 3);
2499 key [0] = GINT_TO_POINTER (2);
2500 key [1] = mono_defaults.marshalbyrefobject_class;
2501 key [2] = extra_class;
2503 key = (void **)g_malloc (sizeof(gpointer) * 2);
2504 key [0] = GINT_TO_POINTER (1);
2505 key [1] = extra_class;
2508 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2509 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2510 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2511 key [1] = remote_class->proxy_class;
2513 // Keep the list of interfaces sorted
2514 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2515 if (extra_class && remote_class->interfaces [i] > extra_class) {
2516 key [j++] = extra_class;
2519 key [j] = remote_class->interfaces [i];
2522 key [j] = extra_class;
2524 // Replace the old class. The interface list is the same
2525 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2526 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2527 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2528 for (i = 0; i < remote_class->interface_count; i++)
2529 key [2 + i] = remote_class->interfaces [i];
2537 * copy_remote_class_key:
2539 * Make a copy of KEY in the domain and return the copy.
2542 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2544 MONO_REQ_GC_NEUTRAL_MODE
2546 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2547 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2549 memcpy (mp_key, key, key_size);
2555 * mono_remote_class:
2556 * @domain: the application domain
2557 * @class_name: name of the remote class
2559 * Creates and initializes a MonoRemoteClass object for a remote type.
2561 * Can raise an exception on failure.
2564 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2566 MONO_REQ_GC_UNSAFE_MODE;
2569 MonoRemoteClass *rc;
2570 gpointer* key, *mp_key;
2573 key = create_remote_class_key (NULL, proxy_class);
2575 mono_domain_lock (domain);
2576 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2580 mono_domain_unlock (domain);
2584 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2585 if (!mono_error_ok (&error)) {
2587 mono_domain_unlock (domain);
2588 mono_error_raise_exception (&error);
2591 mp_key = copy_remote_class_key (domain, key);
2595 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2596 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2597 rc->interface_count = 1;
2598 rc->interfaces [0] = proxy_class;
2599 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2601 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2602 rc->interface_count = 0;
2603 rc->proxy_class = proxy_class;
2606 rc->default_vtable = NULL;
2607 rc->xdomain_vtable = NULL;
2608 rc->proxy_class_name = name;
2609 #ifndef DISABLE_PERFCOUNTERS
2610 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2613 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2615 mono_domain_unlock (domain);
2620 * clone_remote_class:
2621 * Creates a copy of the remote_class, adding the provided class or interface
2623 static MonoRemoteClass*
2624 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2626 MONO_REQ_GC_NEUTRAL_MODE;
2628 MonoRemoteClass *rc;
2629 gpointer* key, *mp_key;
2631 key = create_remote_class_key (remote_class, extra_class);
2632 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2638 mp_key = copy_remote_class_key (domain, key);
2642 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2644 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2645 rc->proxy_class = remote_class->proxy_class;
2646 rc->interface_count = remote_class->interface_count + 1;
2648 // Keep the list of interfaces sorted, since the hash key of
2649 // the remote class depends on this
2650 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2651 if (remote_class->interfaces [i] > extra_class && i == j)
2652 rc->interfaces [j++] = extra_class;
2653 rc->interfaces [j] = remote_class->interfaces [i];
2656 rc->interfaces [j] = extra_class;
2658 // Replace the old class. The interface array is the same
2659 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2660 rc->proxy_class = extra_class;
2661 rc->interface_count = remote_class->interface_count;
2662 if (rc->interface_count > 0)
2663 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2666 rc->default_vtable = NULL;
2667 rc->xdomain_vtable = NULL;
2668 rc->proxy_class_name = remote_class->proxy_class_name;
2670 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2676 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2678 MONO_REQ_GC_UNSAFE_MODE;
2680 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2681 mono_domain_lock (domain);
2682 if (rp->target_domain_id != -1) {
2683 if (remote_class->xdomain_vtable == NULL)
2684 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2685 mono_domain_unlock (domain);
2686 mono_loader_unlock ();
2687 return remote_class->xdomain_vtable;
2689 if (remote_class->default_vtable == NULL) {
2692 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2693 klass = mono_class_from_mono_type (type);
2695 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)))
2696 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2699 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2702 mono_domain_unlock (domain);
2703 mono_loader_unlock ();
2704 return remote_class->default_vtable;
2708 * mono_upgrade_remote_class:
2709 * @domain: the application domain
2710 * @tproxy: the proxy whose remote class has to be upgraded.
2711 * @klass: class to which the remote class can be casted.
2713 * Updates the vtable of the remote class by adding the necessary method slots
2714 * and interface offsets so it can be safely casted to klass. klass can be a
2715 * class or an interface.
2718 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2720 MONO_REQ_GC_UNSAFE_MODE;
2722 MonoTransparentProxy *tproxy;
2723 MonoRemoteClass *remote_class;
2724 gboolean redo_vtable;
2726 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2727 mono_domain_lock (domain);
2729 tproxy = (MonoTransparentProxy*) proxy_object;
2730 remote_class = tproxy->remote_class;
2732 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2735 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2736 if (remote_class->interfaces [i] == klass)
2737 redo_vtable = FALSE;
2740 redo_vtable = (remote_class->proxy_class != klass);
2744 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2745 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2748 mono_domain_unlock (domain);
2749 mono_loader_unlock ();
2751 #endif /* DISABLE_REMOTING */
2755 * mono_object_get_virtual_method:
2756 * @obj: object to operate on.
2759 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2760 * the instance of a callvirt of method.
2763 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2765 MONO_REQ_GC_UNSAFE_MODE;
2768 MonoMethod **vtable;
2769 gboolean is_proxy = FALSE;
2770 MonoMethod *res = NULL;
2772 klass = mono_object_class (obj);
2773 #ifndef DISABLE_REMOTING
2774 if (klass == mono_defaults.transparent_proxy_class) {
2775 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2780 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2783 mono_class_setup_vtable (klass);
2784 vtable = klass->vtable;
2786 if (method->slot == -1) {
2787 /* method->slot might not be set for instances of generic methods */
2788 if (method->is_inflated) {
2789 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2790 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2793 g_assert_not_reached ();
2797 /* check method->slot is a valid index: perform isinstance? */
2798 if (method->slot != -1) {
2799 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2801 gboolean variance_used = FALSE;
2802 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2803 g_assert (iface_offset > 0);
2804 res = vtable [iface_offset + method->slot];
2807 res = vtable [method->slot];
2811 #ifndef DISABLE_REMOTING
2813 /* It may be an interface, abstract class method or generic method */
2814 if (!res || mono_method_signature (res)->generic_param_count)
2817 /* generic methods demand invoke_with_check */
2818 if (mono_method_signature (res)->generic_param_count)
2819 res = mono_marshal_get_remoting_invoke_with_check (res);
2822 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2823 res = mono_cominterop_get_invoke (res);
2826 res = mono_marshal_get_remoting_invoke (res);
2831 if (method->is_inflated) {
2833 /* Have to inflate the result */
2834 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2835 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2845 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2847 g_error ("runtime invoke called on uninitialized runtime");
2851 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2854 * mono_runtime_invoke:
2855 * @method: method to invoke
2856 * @obJ: object instance
2857 * @params: arguments to the method
2858 * @exc: exception information.
2860 * Invokes the method represented by @method on the object @obj.
2862 * obj is the 'this' pointer, it should be NULL for static
2863 * methods, a MonoObject* for object instances and a pointer to
2864 * the value type for value types.
2866 * The params array contains the arguments to the method with the
2867 * same convention: MonoObject* pointers for object instances and
2868 * pointers to the value type otherwise.
2870 * From unmanaged code you'll usually use the
2871 * mono_runtime_invoke() variant.
2873 * Note that this function doesn't handle virtual methods for
2874 * you, it will exec the exact method you pass: we still need to
2875 * expose a function to lookup the derived class implementation
2876 * of a virtual method (there are examples of this in the code,
2879 * You can pass NULL as the exc argument if you don't want to
2880 * catch exceptions, otherwise, *exc will be set to the exception
2881 * thrown, if any. if an exception is thrown, you can't use the
2882 * MonoObject* result from the function.
2884 * If the method returns a value type, it is boxed in an object
2888 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2890 MONO_REQ_GC_UNSAFE_MODE;
2894 if (mono_runtime_get_no_exec ())
2895 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2897 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2898 mono_profiler_method_start_invoke (method);
2900 result = default_mono_runtime_invoke (method, obj, params, exc);
2902 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2903 mono_profiler_method_end_invoke (method);
2909 * mono_method_get_unmanaged_thunk:
2910 * @method: method to generate a thunk for.
2912 * Returns an unmanaged->managed thunk that can be used to call
2913 * a managed method directly from C.
2915 * The thunk's C signature closely matches the managed signature:
2917 * C#: public bool Equals (object obj);
2918 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2919 * MonoObject*, MonoException**);
2921 * The 1st ("this") parameter must not be used with static methods:
2923 * C#: public static bool ReferenceEquals (object a, object b);
2924 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2927 * The last argument must be a non-null pointer of a MonoException* pointer.
2928 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2929 * exception has been thrown in managed code. Otherwise it will point
2930 * to the MonoException* caught by the thunk. In this case, the result of
2931 * the thunk is undefined:
2933 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2934 * MonoException *ex = NULL;
2935 * Equals func = mono_method_get_unmanaged_thunk (method);
2936 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2938 * // handle exception
2941 * The calling convention of the thunk matches the platform's default
2942 * convention. This means that under Windows, C declarations must
2943 * contain the __stdcall attribute:
2945 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2946 * MonoObject*, MonoException**);
2950 * Value type arguments and return values are treated as they were objects:
2952 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2953 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2955 * Arguments must be properly boxed upon trunk's invocation, while return
2956 * values must be unboxed.
2959 mono_method_get_unmanaged_thunk (MonoMethod *method)
2961 MONO_REQ_GC_NEUTRAL_MODE;
2962 MONO_REQ_API_ENTRYPOINT;
2966 MONO_PREPARE_RESET_BLOCKING;
2967 method = mono_marshal_get_thunk_invoke_wrapper (method);
2968 res = mono_compile_method (method);
2969 MONO_FINISH_RESET_BLOCKING;
2975 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2977 MONO_REQ_GC_UNSAFE_MODE;
2981 /* object fields cannot be byref, so we don't need a
2983 gpointer *p = (gpointer*)dest;
2990 case MONO_TYPE_BOOLEAN:
2992 case MONO_TYPE_U1: {
2993 guint8 *p = (guint8*)dest;
2994 *p = value ? *(guint8*)value : 0;
2999 case MONO_TYPE_CHAR: {
3000 guint16 *p = (guint16*)dest;
3001 *p = value ? *(guint16*)value : 0;
3004 #if SIZEOF_VOID_P == 4
3009 case MONO_TYPE_U4: {
3010 gint32 *p = (gint32*)dest;
3011 *p = value ? *(gint32*)value : 0;
3014 #if SIZEOF_VOID_P == 8
3019 case MONO_TYPE_U8: {
3020 gint64 *p = (gint64*)dest;
3021 *p = value ? *(gint64*)value : 0;
3024 case MONO_TYPE_R4: {
3025 float *p = (float*)dest;
3026 *p = value ? *(float*)value : 0;
3029 case MONO_TYPE_R8: {
3030 double *p = (double*)dest;
3031 *p = value ? *(double*)value : 0;
3034 case MONO_TYPE_STRING:
3035 case MONO_TYPE_SZARRAY:
3036 case MONO_TYPE_CLASS:
3037 case MONO_TYPE_OBJECT:
3038 case MONO_TYPE_ARRAY:
3039 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3041 case MONO_TYPE_FNPTR:
3042 case MONO_TYPE_PTR: {
3043 gpointer *p = (gpointer*)dest;
3044 *p = deref_pointer? *(gpointer*)value: value;
3047 case MONO_TYPE_VALUETYPE:
3048 /* note that 't' and 'type->type' can be different */
3049 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3050 t = mono_class_enum_basetype (type->data.klass)->type;
3053 MonoClass *klass = mono_class_from_mono_type (type);
3054 int size = mono_class_value_size (klass, NULL);
3056 mono_gc_bzero_atomic (dest, size);
3058 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3061 case MONO_TYPE_GENERICINST:
3062 t = type->data.generic_class->container_class->byval_arg.type;
3065 g_error ("got type %x", type->type);
3070 * mono_field_set_value:
3071 * @obj: Instance object
3072 * @field: MonoClassField describing the field to set
3073 * @value: The value to be set
3075 * Sets the value of the field described by @field in the object instance @obj
3076 * to the value passed in @value. This method should only be used for instance
3077 * fields. For static fields, use mono_field_static_set_value.
3079 * The value must be on the native format of the field type.
3082 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3084 MONO_REQ_GC_UNSAFE_MODE;
3088 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3090 dest = (char*)obj + field->offset;
3091 mono_copy_value (field->type, dest, value, FALSE);
3095 * mono_field_static_set_value:
3096 * @field: MonoClassField describing the field to set
3097 * @value: The value to be set
3099 * Sets the value of the static field described by @field
3100 * to the value passed in @value.
3102 * The value must be on the native format of the field type.
3105 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3107 MONO_REQ_GC_UNSAFE_MODE;
3111 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3112 /* you cant set a constant! */
3113 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3115 if (field->offset == -1) {
3116 /* Special static */
3119 mono_domain_lock (vt->domain);
3120 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3121 mono_domain_unlock (vt->domain);
3122 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3124 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3126 mono_copy_value (field->type, dest, value, FALSE);
3130 * mono_vtable_get_static_field_data:
3132 * Internal use function: return a pointer to the memory holding the static fields
3133 * for a class or NULL if there are no static fields.
3134 * This is exported only for use by the debugger.
3137 mono_vtable_get_static_field_data (MonoVTable *vt)
3139 MONO_REQ_GC_NEUTRAL_MODE
3141 if (!vt->has_static_fields)
3143 return vt->vtable [vt->klass->vtable_size];
3147 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3149 MONO_REQ_GC_UNSAFE_MODE;
3153 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3154 if (field->offset == -1) {
3155 /* Special static */
3158 mono_domain_lock (vt->domain);
3159 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3160 mono_domain_unlock (vt->domain);
3161 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3163 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3166 src = (guint8*)obj + field->offset;
3173 * mono_field_get_value:
3174 * @obj: Object instance
3175 * @field: MonoClassField describing the field to fetch information from
3176 * @value: pointer to the location where the value will be stored
3178 * Use this routine to get the value of the field @field in the object
3181 * The pointer provided by value must be of the field type, for reference
3182 * types this is a MonoObject*, for value types its the actual pointer to
3187 * mono_field_get_value (obj, int_field, &i);
3190 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3192 MONO_REQ_GC_UNSAFE_MODE;
3198 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3200 src = (char*)obj + field->offset;
3201 mono_copy_value (field->type, value, src, TRUE);
3205 * mono_field_get_value_object:
3206 * @domain: domain where the object will be created (if boxing)
3207 * @field: MonoClassField describing the field to fetch information from
3208 * @obj: The object instance for the field.
3210 * Returns: a new MonoObject with the value from the given field. If the
3211 * field represents a value type, the value is boxed.
3215 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3217 MONO_REQ_GC_UNSAFE_MODE;
3221 MonoVTable *vtable = NULL;
3223 gboolean is_static = FALSE;
3224 gboolean is_ref = FALSE;
3225 gboolean is_literal = FALSE;
3226 gboolean is_ptr = FALSE;
3228 MonoType *type = mono_field_get_type_checked (field, &error);
3230 if (!mono_error_ok (&error))
3231 mono_error_raise_exception (&error);
3233 switch (type->type) {
3234 case MONO_TYPE_STRING:
3235 case MONO_TYPE_OBJECT:
3236 case MONO_TYPE_CLASS:
3237 case MONO_TYPE_ARRAY:
3238 case MONO_TYPE_SZARRAY:
3243 case MONO_TYPE_BOOLEAN:
3246 case MONO_TYPE_CHAR:
3255 case MONO_TYPE_VALUETYPE:
3256 is_ref = type->byref;
3258 case MONO_TYPE_GENERICINST:
3259 is_ref = !mono_type_generic_inst_is_valuetype (type);
3265 g_error ("type 0x%x not handled in "
3266 "mono_field_get_value_object", type->type);
3270 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3273 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3277 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3278 if (!vtable->initialized)
3279 mono_runtime_class_init (vtable);
3287 get_default_field_value (domain, field, &o);
3288 } else if (is_static) {
3289 mono_field_static_get_value (vtable, field, &o);
3291 mono_field_get_value (obj, field, &o);
3297 static MonoMethod *m;
3303 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3304 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3310 get_default_field_value (domain, field, v);
3311 } else if (is_static) {
3312 mono_field_static_get_value (vtable, field, v);
3314 mono_field_get_value (obj, field, v);
3317 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3318 args [0] = ptr ? *ptr : NULL;
3319 args [1] = mono_type_get_object (mono_domain_get (), type);
3321 return mono_runtime_invoke (m, NULL, args, NULL);
3324 /* boxed value type */
3325 klass = mono_class_from_mono_type (type);
3327 if (mono_class_is_nullable (klass))
3328 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3330 o = mono_object_new (domain, klass);
3331 v = ((gchar *) o) + sizeof (MonoObject);
3334 get_default_field_value (domain, field, v);
3335 } else if (is_static) {
3336 mono_field_static_get_value (vtable, field, v);
3338 mono_field_get_value (obj, field, v);
3345 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3347 MONO_REQ_GC_UNSAFE_MODE;
3350 const char *p = blob;
3351 mono_metadata_decode_blob_size (p, &p);
3354 case MONO_TYPE_BOOLEAN:
3357 *(guint8 *) value = *p;
3359 case MONO_TYPE_CHAR:
3362 *(guint16*) value = read16 (p);
3366 *(guint32*) value = read32 (p);
3370 *(guint64*) value = read64 (p);
3373 readr4 (p, (float*) value);
3376 readr8 (p, (double*) value);
3378 case MONO_TYPE_STRING:
3379 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3381 case MONO_TYPE_CLASS:
3382 *(gpointer*) value = NULL;
3386 g_warning ("type 0x%02x should not be in constant table", type);
3392 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3394 MONO_REQ_GC_NEUTRAL_MODE;
3396 MonoTypeEnum def_type;
3399 data = mono_class_get_field_default_value (field, &def_type);
3400 mono_get_constant_value_from_blob (domain, def_type, data, value);
3404 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3406 MONO_REQ_GC_UNSAFE_MODE;
3410 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3412 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3413 get_default_field_value (vt->domain, field, value);
3417 if (field->offset == -1) {
3418 /* Special static */
3419 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3420 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3422 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3424 mono_copy_value (field->type, value, src, TRUE);
3428 * mono_field_static_get_value:
3429 * @vt: vtable to the object
3430 * @field: MonoClassField describing the field to fetch information from
3431 * @value: where the value is returned
3433 * Use this routine to get the value of the static field @field value.
3435 * The pointer provided by value must be of the field type, for reference
3436 * types this is a MonoObject*, for value types its the actual pointer to
3441 * mono_field_static_get_value (vt, int_field, &i);
3444 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3446 MONO_REQ_GC_NEUTRAL_MODE;
3448 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3452 * mono_property_set_value:
3453 * @prop: MonoProperty to set
3454 * @obj: instance object on which to act
3455 * @params: parameters to pass to the propery
3456 * @exc: optional exception
3458 * Invokes the property's set method with the given arguments on the
3459 * object instance obj (or NULL for static properties).
3461 * You can pass NULL as the exc argument if you don't want to
3462 * catch exceptions, otherwise, *exc will be set to the exception
3463 * thrown, if any. if an exception is thrown, you can't use the
3464 * MonoObject* result from the function.
3467 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3469 MONO_REQ_GC_UNSAFE_MODE;
3471 default_mono_runtime_invoke (prop->set, obj, params, exc);
3475 * mono_property_get_value:
3476 * @prop: MonoProperty to fetch
3477 * @obj: instance object on which to act
3478 * @params: parameters to pass to the propery
3479 * @exc: optional exception
3481 * Invokes the property's get method with the given arguments on the
3482 * object instance obj (or NULL for static properties).
3484 * You can pass NULL as the exc argument if you don't want to
3485 * catch exceptions, otherwise, *exc will be set to the exception
3486 * thrown, if any. if an exception is thrown, you can't use the
3487 * MonoObject* result from the function.
3489 * Returns: the value from invoking the get method on the property.
3492 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3494 MONO_REQ_GC_UNSAFE_MODE;
3496 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3500 * mono_nullable_init:
3501 * @buf: The nullable structure to initialize.
3502 * @value: the value to initialize from
3503 * @klass: the type for the object
3505 * Initialize the nullable structure pointed to by @buf from @value which
3506 * should be a boxed value type. The size of @buf should be able to hold
3507 * as much data as the @klass->instance_size (which is the number of bytes
3508 * that will be copies).
3510 * Since Nullables have variable structure, we can not define a C
3511 * structure for them.
3514 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3516 MONO_REQ_GC_UNSAFE_MODE;
3518 MonoClass *param_class = klass->cast_class;
3520 mono_class_setup_fields_locking (klass);
3521 g_assert (klass->fields_inited);
3523 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3524 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3526 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3528 if (param_class->has_references)
3529 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3531 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3533 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3538 * mono_nullable_box:
3539 * @buf: The buffer representing the data to be boxed
3540 * @klass: the type to box it as.
3542 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3546 mono_nullable_box (guint8 *buf, MonoClass *klass)
3548 MONO_REQ_GC_UNSAFE_MODE;
3550 MonoClass *param_class = klass->cast_class;
3552 mono_class_setup_fields_locking (klass);
3553 g_assert (klass->fields_inited);
3555 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3556 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3558 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3559 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3560 if (param_class->has_references)
3561 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3563 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3571 * mono_get_delegate_invoke:
3572 * @klass: The delegate class
3574 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3577 mono_get_delegate_invoke (MonoClass *klass)
3579 MONO_REQ_GC_NEUTRAL_MODE;
3583 /* This is called at runtime, so avoid the slower search in metadata */
3584 mono_class_setup_methods (klass);
3585 if (klass->exception_type)
3587 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3592 * mono_get_delegate_begin_invoke:
3593 * @klass: The delegate class
3595 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3598 mono_get_delegate_begin_invoke (MonoClass *klass)
3600 MONO_REQ_GC_NEUTRAL_MODE;
3604 /* This is called at runtime, so avoid the slower search in metadata */
3605 mono_class_setup_methods (klass);
3606 if (klass->exception_type)
3608 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3613 * mono_get_delegate_end_invoke:
3614 * @klass: The delegate class
3616 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3619 mono_get_delegate_end_invoke (MonoClass *klass)
3621 MONO_REQ_GC_NEUTRAL_MODE;
3625 /* This is called at runtime, so avoid the slower search in metadata */
3626 mono_class_setup_methods (klass);
3627 if (klass->exception_type)
3629 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3634 * mono_runtime_delegate_invoke:
3635 * @delegate: pointer to a delegate object.
3636 * @params: parameters for the delegate.
3637 * @exc: Pointer to the exception result.
3639 * Invokes the delegate method @delegate with the parameters provided.
3641 * You can pass NULL as the exc argument if you don't want to
3642 * catch exceptions, otherwise, *exc will be set to the exception
3643 * thrown, if any. if an exception is thrown, you can't use the
3644 * MonoObject* result from the function.
3647 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3649 MONO_REQ_GC_UNSAFE_MODE;
3652 MonoClass *klass = delegate->vtable->klass;
3654 im = mono_get_delegate_invoke (klass);
3656 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3658 return mono_runtime_invoke (im, delegate, params, exc);
3661 static char **main_args = NULL;
3662 static int num_main_args = 0;
3665 * mono_runtime_get_main_args:
3667 * Returns: a MonoArray with the arguments passed to the main program
3670 mono_runtime_get_main_args (void)
3672 MONO_REQ_GC_UNSAFE_MODE;
3676 MonoDomain *domain = mono_domain_get ();
3678 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3680 for (i = 0; i < num_main_args; ++i)
3681 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3687 free_main_args (void)
3689 MONO_REQ_GC_NEUTRAL_MODE;
3693 for (i = 0; i < num_main_args; ++i)
3694 g_free (main_args [i]);
3701 * mono_runtime_set_main_args:
3702 * @argc: number of arguments from the command line
3703 * @argv: array of strings from the command line
3705 * Set the command line arguments from an embedding application that doesn't otherwise call
3706 * mono_runtime_run_main ().
3709 mono_runtime_set_main_args (int argc, char* argv[])
3711 MONO_REQ_GC_NEUTRAL_MODE;
3716 main_args = g_new0 (char*, argc);
3717 num_main_args = argc;
3719 for (i = 0; i < argc; ++i) {
3722 utf8_arg = mono_utf8_from_external (argv[i]);
3723 if (utf8_arg == NULL) {
3724 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3725 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3729 main_args [i] = utf8_arg;
3736 * mono_runtime_run_main:
3737 * @method: the method to start the application with (usually Main)
3738 * @argc: number of arguments from the command line
3739 * @argv: array of strings from the command line
3740 * @exc: excetption results
3742 * Execute a standard Main() method (argc/argv contains the
3743 * executable name). This method also sets the command line argument value
3744 * needed by System.Environment.
3749 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3752 MONO_REQ_GC_UNSAFE_MODE;
3755 MonoArray *args = NULL;
3756 MonoDomain *domain = mono_domain_get ();
3757 gchar *utf8_fullpath;
3758 MonoMethodSignature *sig;
3760 g_assert (method != NULL);
3762 mono_thread_set_main (mono_thread_current ());
3764 main_args = g_new0 (char*, argc);
3765 num_main_args = argc;
3767 if (!g_path_is_absolute (argv [0])) {
3768 gchar *basename = g_path_get_basename (argv [0]);
3769 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3773 utf8_fullpath = mono_utf8_from_external (fullpath);
3774 if(utf8_fullpath == NULL) {
3775 /* Printing the arg text will cause glib to
3776 * whinge about "Invalid UTF-8", but at least
3777 * its relevant, and shows the problem text
3780 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3781 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3788 utf8_fullpath = mono_utf8_from_external (argv[0]);
3789 if(utf8_fullpath == NULL) {
3790 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3791 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3796 main_args [0] = utf8_fullpath;
3798 for (i = 1; i < argc; ++i) {
3801 utf8_arg=mono_utf8_from_external (argv[i]);
3802 if(utf8_arg==NULL) {
3803 /* Ditto the comment about Invalid UTF-8 here */
3804 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3805 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3809 main_args [i] = utf8_arg;
3814 sig = mono_method_signature (method);
3816 g_print ("Unable to load Main method.\n");
3820 if (sig->param_count) {
3821 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3822 for (i = 0; i < argc; ++i) {
3823 /* The encodings should all work, given that
3824 * we've checked all these args for the
3827 gchar *str = mono_utf8_from_external (argv [i]);
3828 MonoString *arg = mono_string_new (domain, str);
3829 mono_array_setref (args, i, arg);
3833 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3836 mono_assembly_set_main (method->klass->image->assembly);
3838 return mono_runtime_exec_main (method, args, exc);
3842 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3844 static MonoMethod *serialize_method;
3849 if (!serialize_method) {
3850 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3851 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3854 if (!serialize_method) {
3859 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3863 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3871 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3873 MONO_REQ_GC_UNSAFE_MODE;
3875 static MonoMethod *deserialize_method;
3880 if (!deserialize_method) {
3881 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3882 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3884 if (!deserialize_method) {
3891 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3898 #ifndef DISABLE_REMOTING
3900 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3902 MONO_REQ_GC_UNSAFE_MODE;
3904 static MonoMethod *get_proxy_method;
3906 MonoDomain *domain = mono_domain_get ();
3907 MonoRealProxy *real_proxy;
3908 MonoReflectionType *reflection_type;
3909 MonoTransparentProxy *transparent_proxy;
3911 if (!get_proxy_method)
3912 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3914 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3916 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3917 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3919 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3920 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3923 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3927 return (MonoObject*) transparent_proxy;
3929 #endif /* DISABLE_REMOTING */
3932 * mono_object_xdomain_representation
3934 * @target_domain: a domain
3935 * @exc: pointer to a MonoObject*
3937 * Creates a representation of obj in the domain target_domain. This
3938 * is either a copy of obj arrived through via serialization and
3939 * deserialization or a proxy, depending on whether the object is
3940 * serializable or marshal by ref. obj must not be in target_domain.
3942 * If the object cannot be represented in target_domain, NULL is
3943 * returned and *exc is set to an appropriate exception.
3946 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3948 MONO_REQ_GC_UNSAFE_MODE;
3950 MonoObject *deserialized = NULL;
3951 gboolean failure = FALSE;
3955 #ifndef DISABLE_REMOTING
3956 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3957 deserialized = make_transparent_proxy (obj, &failure, exc);
3962 MonoDomain *domain = mono_domain_get ();
3963 MonoObject *serialized;
3965 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3966 serialized = serialize_object (obj, &failure, exc);
3967 mono_domain_set_internal_with_options (target_domain, FALSE);
3969 deserialized = deserialize_object (serialized, &failure, exc);
3970 if (domain != target_domain)
3971 mono_domain_set_internal_with_options (domain, FALSE);
3974 return deserialized;
3977 /* Used in call_unhandled_exception_delegate */
3979 create_unhandled_exception_eventargs (MonoObject *exc)
3981 MONO_REQ_GC_UNSAFE_MODE;
3985 MonoMethod *method = NULL;
3986 MonoBoolean is_terminating = TRUE;
3989 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3992 mono_class_init (klass);
3994 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3995 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3999 args [1] = &is_terminating;
4001 obj = mono_object_new (mono_domain_get (), klass);
4002 mono_runtime_invoke (method, obj, args, NULL);
4007 /* Used in mono_unhandled_exception */
4009 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4010 MONO_REQ_GC_UNSAFE_MODE;
4012 MonoObject *e = NULL;
4014 MonoDomain *current_domain = mono_domain_get ();
4016 if (domain != current_domain)
4017 mono_domain_set_internal_with_options (domain, FALSE);
4019 g_assert (domain == mono_object_domain (domain->domain));
4021 if (mono_object_domain (exc) != domain) {
4022 MonoObject *serialization_exc;
4024 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4026 if (serialization_exc) {
4028 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4031 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4032 "System.Runtime.Serialization", "SerializationException",
4033 "Could not serialize unhandled exception.");
4037 g_assert (mono_object_domain (exc) == domain);
4039 pa [0] = domain->domain;
4040 pa [1] = create_unhandled_exception_eventargs (exc);
4041 mono_runtime_delegate_invoke (delegate, pa, &e);
4043 if (domain != current_domain)
4044 mono_domain_set_internal_with_options (current_domain, FALSE);
4048 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4049 if (!mono_error_ok (&error)) {
4050 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4051 mono_error_cleanup (&error);
4053 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4059 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4062 * mono_runtime_unhandled_exception_policy_set:
4063 * @policy: the new policy
4065 * This is a VM internal routine.
4067 * Sets the runtime policy for handling unhandled exceptions.
4070 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4071 runtime_unhandled_exception_policy = policy;
4075 * mono_runtime_unhandled_exception_policy_get:
4077 * This is a VM internal routine.
4079 * Gets the runtime policy for handling unhandled exceptions.
4081 MonoRuntimeUnhandledExceptionPolicy
4082 mono_runtime_unhandled_exception_policy_get (void) {
4083 return runtime_unhandled_exception_policy;
4087 * mono_unhandled_exception:
4088 * @exc: exception thrown
4090 * This is a VM internal routine.
4092 * We call this function when we detect an unhandled exception
4093 * in the default domain.
4095 * It invokes the * UnhandledException event in AppDomain or prints
4096 * a warning to the console
4099 mono_unhandled_exception (MonoObject *exc)
4101 MONO_REQ_GC_UNSAFE_MODE;
4103 MonoClassField *field;
4104 MonoDomain *current_domain, *root_domain;
4105 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4107 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4110 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4113 current_domain = mono_domain_get ();
4114 root_domain = mono_get_root_domain ();
4116 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4117 if (current_domain != root_domain)
4118 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4120 /* set exitcode only if we will abort the process */
4121 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4122 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4123 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4125 mono_environment_exitcode_set (1);
4128 mono_print_unhandled_exception (exc);
4130 if (root_appdomain_delegate)
4131 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4132 if (current_appdomain_delegate)
4133 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4138 * mono_runtime_exec_managed_code:
4139 * @domain: Application domain
4140 * @main_func: function to invoke from the execution thread
4141 * @main_args: parameter to the main_func
4143 * Launch a new thread to execute a function
4145 * main_func is called back from the thread with main_args as the
4146 * parameter. The callback function is expected to start Main()
4147 * eventually. This function then waits for all managed threads to
4149 * It is not necesseray anymore to execute managed code in a subthread,
4150 * so this function should not be used anymore by default: just
4151 * execute the code and then call mono_thread_manage ().
4154 mono_runtime_exec_managed_code (MonoDomain *domain,
4155 MonoMainThreadFunc main_func,
4158 mono_thread_create (domain, main_func, main_args);
4160 mono_thread_manage ();
4164 * Execute a standard Main() method (args doesn't contain the
4168 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4170 MONO_REQ_GC_UNSAFE_MODE;
4175 MonoCustomAttrInfo* cinfo;
4176 gboolean has_stathread_attribute;
4177 MonoInternalThread* thread = mono_thread_internal_current ();
4183 domain = mono_object_domain (args);
4184 if (!domain->entry_assembly) {
4186 MonoAssembly *assembly;
4188 assembly = method->klass->image->assembly;
4189 domain->entry_assembly = assembly;
4190 /* Domains created from another domain already have application_base and configuration_file set */
4191 if (domain->setup->application_base == NULL) {
4192 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4195 if (domain->setup->configuration_file == NULL) {
4196 str = g_strconcat (assembly->image->name, ".config", NULL);
4197 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4199 mono_domain_set_options_from_config (domain);
4203 cinfo = mono_custom_attrs_from_method (method);
4205 static MonoClass *stathread_attribute = NULL;
4206 if (!stathread_attribute)
4207 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4208 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4210 mono_custom_attrs_free (cinfo);
4212 has_stathread_attribute = FALSE;
4214 if (has_stathread_attribute) {
4215 thread->apartment_state = ThreadApartmentState_STA;
4217 thread->apartment_state = ThreadApartmentState_MTA;
4219 mono_thread_init_apartment_state ();
4221 /* FIXME: check signature of method */
4222 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4224 res = mono_runtime_invoke (method, NULL, pa, exc);
4226 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4230 mono_environment_exitcode_set (rval);
4232 mono_runtime_invoke (method, NULL, pa, exc);
4236 /* If the return type of Main is void, only
4237 * set the exitcode if an exception was thrown
4238 * (we don't want to blow away an
4239 * explicitly-set exit code)
4242 mono_environment_exitcode_set (rval);
4250 * mono_install_runtime_invoke:
4251 * @func: Function to install
4253 * This is a VM internal routine
4256 mono_install_runtime_invoke (MonoInvokeFunc func)
4258 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4263 * mono_runtime_invoke_array:
4264 * @method: method to invoke
4265 * @obJ: object instance
4266 * @params: arguments to the method
4267 * @exc: exception information.
4269 * Invokes the method represented by @method on the object @obj.
4271 * obj is the 'this' pointer, it should be NULL for static
4272 * methods, a MonoObject* for object instances and a pointer to
4273 * the value type for value types.
4275 * The params array contains the arguments to the method with the
4276 * same convention: MonoObject* pointers for object instances and
4277 * pointers to the value type otherwise. The _invoke_array
4278 * variant takes a C# object[] as the params argument (MonoArray
4279 * *params): in this case the value types are boxed inside the
4280 * respective reference representation.
4282 * From unmanaged code you'll usually use the
4283 * mono_runtime_invoke() variant.
4285 * Note that this function doesn't handle virtual methods for
4286 * you, it will exec the exact method you pass: we still need to
4287 * expose a function to lookup the derived class implementation
4288 * of a virtual method (there are examples of this in the code,
4291 * You can pass NULL as the exc argument if you don't want to
4292 * catch exceptions, otherwise, *exc will be set to the exception
4293 * thrown, if any. if an exception is thrown, you can't use the
4294 * MonoObject* result from the function.
4296 * If the method returns a value type, it is boxed in an object
4300 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4303 MONO_REQ_GC_UNSAFE_MODE;
4305 MonoMethodSignature *sig = mono_method_signature (method);
4306 gpointer *pa = NULL;
4309 gboolean has_byref_nullables = FALSE;
4311 if (NULL != params) {
4312 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4313 for (i = 0; i < mono_array_length (params); i++) {
4314 MonoType *t = sig->params [i];
4320 case MONO_TYPE_BOOLEAN:
4323 case MONO_TYPE_CHAR:
4332 case MONO_TYPE_VALUETYPE:
4333 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4334 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4335 pa [i] = mono_array_get (params, MonoObject*, i);
4337 has_byref_nullables = TRUE;
4339 /* MS seems to create the objects if a null is passed in */
4340 if (!mono_array_get (params, MonoObject*, i))
4341 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4345 * We can't pass the unboxed vtype byref to the callee, since
4346 * that would mean the callee would be able to modify boxed
4347 * primitive types. So we (and MS) make a copy of the boxed
4348 * object, pass that to the callee, and replace the original
4349 * boxed object in the arg array with the copy.
4351 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4352 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4353 mono_array_setref (params, i, copy);
4356 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4359 case MONO_TYPE_STRING:
4360 case MONO_TYPE_OBJECT:
4361 case MONO_TYPE_CLASS:
4362 case MONO_TYPE_ARRAY:
4363 case MONO_TYPE_SZARRAY:
4365 pa [i] = mono_array_addr (params, MonoObject*, i);
4366 // FIXME: I need to check this code path
4368 pa [i] = mono_array_get (params, MonoObject*, i);
4370 case MONO_TYPE_GENERICINST:
4372 t = &t->data.generic_class->container_class->this_arg;
4374 t = &t->data.generic_class->container_class->byval_arg;
4376 case MONO_TYPE_PTR: {
4379 /* The argument should be an IntPtr */
4380 arg = mono_array_get (params, MonoObject*, i);
4384 g_assert (arg->vtable->klass == mono_defaults.int_class);
4385 pa [i] = ((MonoIntPtr*)arg)->m_value;
4390 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4395 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4398 if (mono_class_is_nullable (method->klass)) {
4399 /* Need to create a boxed vtype instead */
4405 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4409 obj = mono_object_new (mono_domain_get (), method->klass);
4410 g_assert (obj); /*maybe we should raise a TLE instead?*/
4411 #ifndef DISABLE_REMOTING
4412 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4413 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4416 if (method->klass->valuetype)
4417 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4420 } else if (method->klass->valuetype) {
4421 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4424 mono_runtime_invoke (method, o, pa, exc);
4425 return (MonoObject *)obj;
4427 if (mono_class_is_nullable (method->klass)) {
4428 MonoObject *nullable;
4430 /* Convert the unboxed vtype into a Nullable structure */
4431 nullable = mono_object_new (mono_domain_get (), method->klass);
4433 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4434 obj = mono_object_unbox (nullable);
4437 /* obj must be already unboxed if needed */
4438 res = mono_runtime_invoke (method, obj, pa, exc);
4440 if (sig->ret->type == MONO_TYPE_PTR) {
4441 MonoClass *pointer_class;
4442 static MonoMethod *box_method;
4444 MonoObject *box_exc;
4447 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4448 * convert it to a Pointer object.
4450 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4452 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4454 g_assert (res->vtable->klass == mono_defaults.int_class);
4455 box_args [0] = ((MonoIntPtr*)res)->m_value;
4456 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4457 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4458 g_assert (!box_exc);
4461 if (has_byref_nullables) {
4463 * The runtime invoke wrapper already converted byref nullables back,
4464 * and stored them in pa, we just need to copy them back to the
4467 for (i = 0; i < mono_array_length (params); i++) {
4468 MonoType *t = sig->params [i];
4470 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4471 mono_array_setref (params, i, pa [i]);
4481 * @klass: the class of the object that we want to create
4483 * Returns: a newly created object whose definition is
4484 * looked up using @klass. This will not invoke any constructors,
4485 * so the consumer of this routine has to invoke any constructors on
4486 * its own to initialize the object.
4488 * It returns NULL on failure.
4491 mono_object_new (MonoDomain *domain, MonoClass *klass)
4493 MONO_REQ_GC_UNSAFE_MODE;
4497 vtable = mono_class_vtable (domain, klass);
4502 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4503 mono_error_raise_exception (&error); /* FIXME don't raise here */
4509 * mono_object_new_pinned:
4511 * Same as mono_object_new, but the returned object will be pinned.
4512 * For SGEN, these objects will only be freed at appdomain unload.
4515 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4517 MONO_REQ_GC_UNSAFE_MODE;
4521 mono_error_init (error);
4523 vtable = mono_class_vtable (domain, klass);
4524 g_assert (vtable); /* FIXME don't swallow the error */
4526 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4528 if (G_UNLIKELY (!o))
4529 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4530 else if (G_UNLIKELY (vtable->klass->has_finalize))
4531 mono_object_register_finalizer (o);
4537 * mono_object_new_specific:
4538 * @vtable: the vtable of the object that we want to create
4540 * Returns: A newly created object with class and domain specified
4544 mono_object_new_specific (MonoVTable *vtable)
4547 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4548 mono_error_raise_exception (&error);
4554 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4556 MONO_REQ_GC_UNSAFE_MODE;
4560 mono_error_init (error);
4562 /* check for is_com_object for COM Interop */
4563 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4566 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4569 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4572 mono_class_init (klass);
4574 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4576 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4579 vtable->domain->create_proxy_for_type_method = im;
4582 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4584 o = mono_runtime_invoke (im, NULL, pa, NULL);
4585 if (o != NULL) return o;
4588 return mono_object_new_alloc_specific_checked (vtable, error);
4592 ves_icall_object_new_specific (MonoVTable *vtable)
4595 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4596 mono_error_raise_exception (&error);
4602 mono_object_new_alloc_specific (MonoVTable *vtable)
4605 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4606 mono_error_raise_exception (&error);
4612 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4614 MONO_REQ_GC_UNSAFE_MODE;
4618 mono_error_init (error);
4620 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4622 if (G_UNLIKELY (!o))
4623 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4624 else if (G_UNLIKELY (vtable->klass->has_finalize))
4625 mono_object_register_finalizer (o);
4631 mono_object_new_fast (MonoVTable *vtable)
4634 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4635 mono_error_raise_exception (&error);
4641 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4643 MONO_REQ_GC_UNSAFE_MODE;
4647 mono_error_init (error);
4649 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4651 if (G_UNLIKELY (!o))
4652 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4658 ves_icall_object_new_fast (MonoVTable *vtable)
4661 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4662 mono_error_raise_exception (&error);
4668 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4670 MONO_REQ_GC_UNSAFE_MODE;
4674 mono_error_init (error);
4676 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4678 if (G_UNLIKELY (!o))
4679 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4680 else if (G_UNLIKELY (vtable->klass->has_finalize))
4681 mono_object_register_finalizer (o);
4687 * mono_class_get_allocation_ftn:
4689 * @for_box: the object will be used for boxing
4690 * @pass_size_in_words:
4692 * Return the allocation function appropriate for the given class.
4696 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4698 MONO_REQ_GC_NEUTRAL_MODE;
4700 *pass_size_in_words = FALSE;
4702 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4703 return ves_icall_object_new_specific;
4705 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4707 return ves_icall_object_new_fast;
4710 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4711 * of the overhead of parameter passing.
4714 *pass_size_in_words = TRUE;
4715 #ifdef GC_REDIRECT_TO_LOCAL
4716 return GC_local_gcj_fast_malloc;
4718 return GC_gcj_fast_malloc;
4723 return ves_icall_object_new_specific;
4727 * mono_object_new_from_token:
4728 * @image: Context where the type_token is hosted
4729 * @token: a token of the type that we want to create
4731 * Returns: A newly created object whose definition is
4732 * looked up using @token in the @image image
4735 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4737 MONO_REQ_GC_UNSAFE_MODE;
4742 klass = mono_class_get_checked (image, token, &error);
4743 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4745 return mono_object_new (domain, klass);
4750 * mono_object_clone:
4751 * @obj: the object to clone
4753 * Returns: A newly created object who is a shallow copy of @obj
4756 mono_object_clone (MonoObject *obj)
4759 MonoObject *o = mono_object_clone_checked (obj, &error);
4760 mono_error_raise_exception (&error);
4766 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4768 MONO_REQ_GC_UNSAFE_MODE;
4773 mono_error_init (error);
4775 size = obj->vtable->klass->instance_size;
4777 if (obj->vtable->klass->rank)
4778 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4780 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4782 if (G_UNLIKELY (!o)) {
4783 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4787 /* If the object doesn't contain references this will do a simple memmove. */
4788 mono_gc_wbarrier_object_copy (o, obj);
4790 if (obj->vtable->klass->has_finalize)
4791 mono_object_register_finalizer (o);
4796 * mono_array_full_copy:
4797 * @src: source array to copy
4798 * @dest: destination array
4800 * Copies the content of one array to another with exactly the same type and size.
4803 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4805 MONO_REQ_GC_UNSAFE_MODE;
4808 MonoClass *klass = src->obj.vtable->klass;
4810 g_assert (klass == dest->obj.vtable->klass);
4812 size = mono_array_length (src);
4813 g_assert (size == mono_array_length (dest));
4814 size *= mono_array_element_size (klass);
4816 if (klass->element_class->valuetype) {
4817 if (klass->element_class->has_references)
4818 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4820 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4822 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4825 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4830 * mono_array_clone_in_domain:
4831 * @domain: the domain in which the array will be cloned into
4832 * @array: the array to clone
4834 * This routine returns a copy of the array that is hosted on the
4835 * specified MonoDomain.
4838 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4840 MONO_REQ_GC_UNSAFE_MODE;
4846 MonoClass *klass = array->obj.vtable->klass;
4848 if (array->bounds == NULL) {
4849 size = mono_array_length (array);
4850 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
4851 mono_error_raise_exception (&error); /* FIXME don't raise here */
4853 size *= mono_array_element_size (klass);
4855 if (klass->element_class->valuetype) {
4856 if (klass->element_class->has_references)
4857 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4859 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4861 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4864 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4869 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4870 size = mono_array_element_size (klass);
4871 for (i = 0; i < klass->rank; ++i) {
4872 sizes [i] = array->bounds [i].length;
4873 size *= array->bounds [i].length;
4874 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4876 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
4877 mono_error_raise_exception (&error); /* FIXME don't raise here */
4879 if (klass->element_class->valuetype) {
4880 if (klass->element_class->has_references)
4881 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4883 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4885 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4888 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4896 * @array: the array to clone
4898 * Returns: A newly created array who is a shallow copy of @array
4901 mono_array_clone (MonoArray *array)
4903 MONO_REQ_GC_UNSAFE_MODE;
4905 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4908 /* helper macros to check for overflow when calculating the size of arrays */
4909 #ifdef MONO_BIG_ARRAYS
4910 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4911 #define MYGUINT_MAX MYGUINT64_MAX
4912 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4913 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4914 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4915 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4916 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4918 #define MYGUINT32_MAX 4294967295U
4919 #define MYGUINT_MAX MYGUINT32_MAX
4920 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4921 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4922 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4923 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4924 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4928 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4930 MONO_REQ_GC_NEUTRAL_MODE;
4934 byte_len = mono_array_element_size (klass);
4935 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4938 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4940 byte_len += MONO_SIZEOF_MONO_ARRAY;
4948 * mono_array_new_full:
4949 * @domain: domain where the object is created
4950 * @array_class: array class
4951 * @lengths: lengths for each dimension in the array
4952 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4954 * This routine creates a new array objects with the given dimensions,
4955 * lower bounds and type.
4958 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4961 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
4962 mono_error_raise_exception (&error);
4968 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
4970 MONO_REQ_GC_UNSAFE_MODE;
4972 uintptr_t byte_len = 0, len, bounds_size;
4975 MonoArrayBounds *bounds;
4979 mono_error_init (error);
4981 if (!array_class->inited)
4982 mono_class_init (array_class);
4986 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4987 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4989 if (len > MONO_ARRAY_MAX_INDEX) {
4990 mono_error_set_generic_error (error, "System", "OverflowException", "");
4995 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4997 for (i = 0; i < array_class->rank; ++i) {
4998 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
4999 mono_error_set_generic_error (error, "System", "OverflowException", "");
5002 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5003 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5010 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5011 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5017 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5018 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5021 byte_len = (byte_len + 3) & ~3;
5022 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5023 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5026 byte_len += bounds_size;
5029 * Following three lines almost taken from mono_object_new ():
5030 * they need to be kept in sync.
5032 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5034 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5036 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5038 if (G_UNLIKELY (!o)) {
5039 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5043 array = (MonoArray*)o;
5045 bounds = array->bounds;
5048 for (i = 0; i < array_class->rank; ++i) {
5049 bounds [i].length = lengths [i];
5051 bounds [i].lower_bound = lower_bounds [i];
5060 * @domain: domain where the object is created
5061 * @eclass: element class
5062 * @n: number of array elements
5064 * This routine creates a new szarray with @n elements of type @eclass.
5067 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5069 MONO_REQ_GC_UNSAFE_MODE;
5075 ac = mono_array_class_get (eclass, 1);
5078 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5079 mono_error_raise_exception (&error); /* FIXME don't raise here */
5085 * mono_array_new_specific:
5086 * @vtable: a vtable in the appropriate domain for an initialized class
5087 * @n: number of array elements
5089 * This routine is a fast alternative to mono_array_new() for code which
5090 * can be sure about the domain it operates in.
5093 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5096 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5097 mono_error_raise_exception (&error); /* FIXME don't raise here */
5103 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5105 MONO_REQ_GC_UNSAFE_MODE;
5110 mono_error_init (error);
5112 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5113 mono_error_set_generic_error (error, "System", "OverflowException", "");
5117 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5118 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5121 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5123 if (G_UNLIKELY (!o)) {
5124 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5128 return (MonoArray*)o;
5132 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5135 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5136 mono_error_raise_exception (&error);
5142 * mono_string_new_utf16:
5143 * @text: a pointer to an utf16 string
5144 * @len: the length of the string
5146 * Returns: A newly created string object which contains @text.
5149 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5151 MONO_REQ_GC_UNSAFE_MODE;
5156 s = mono_string_new_size_checked (domain, len, &error);
5157 mono_error_raise_exception (&error); /* FIXME don't raise here */
5159 memcpy (mono_string_chars (s), text, len * 2);
5165 * mono_string_new_utf32:
5166 * @text: a pointer to an utf32 string
5167 * @len: the length of the string
5169 * Returns: A newly created string object which contains @text.
5172 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5174 MONO_REQ_GC_UNSAFE_MODE;
5178 mono_unichar2 *utf16_output = NULL;
5179 gint32 utf16_len = 0;
5180 GError *gerror = NULL;
5181 glong items_written;
5183 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5186 g_error_free (gerror);
5188 while (utf16_output [utf16_len]) utf16_len++;
5190 s = mono_string_new_size_checked (domain, utf16_len, &error);
5191 mono_error_raise_exception (&error); /* FIXME don't raise here */
5193 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5195 g_free (utf16_output);
5201 * mono_string_new_size:
5202 * @text: a pointer to an utf16 string
5203 * @len: the length of the string
5205 * Returns: A newly created string object of @len
5208 mono_string_new_size (MonoDomain *domain, gint32 len)
5211 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5212 mono_error_raise_exception (&error);
5218 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5220 MONO_REQ_GC_UNSAFE_MODE;
5226 mono_error_init (error);
5228 /* check for overflow */
5229 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5230 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5234 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5235 g_assert (size > 0);
5237 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5240 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5242 if (G_UNLIKELY (!s)) {
5243 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5251 * mono_string_new_len:
5252 * @text: a pointer to an utf8 string
5253 * @length: number of bytes in @text to consider
5255 * Returns: A newly created string object which contains @text.
5258 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5260 MONO_REQ_GC_UNSAFE_MODE;
5262 GError *error = NULL;
5263 MonoString *o = NULL;
5265 glong items_written;
5267 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5270 o = mono_string_new_utf16 (domain, ut, items_written);
5272 g_error_free (error);
5281 * @text: a pointer to an utf8 string
5283 * Returns: A newly created string object which contains @text.
5286 mono_string_new (MonoDomain *domain, const char *text)
5288 MONO_REQ_GC_UNSAFE_MODE;
5290 GError *error = NULL;
5291 MonoString *o = NULL;
5293 glong items_written;
5298 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5301 o = mono_string_new_utf16 (domain, ut, items_written);
5303 g_error_free (error);
5306 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5312 MonoString *o = NULL;
5314 if (!g_utf8_validate (text, -1, &end))
5317 len = g_utf8_strlen (text, -1);
5318 o = mono_string_new_size_checked (domain, len, &error);
5319 mono_error_raise_exception (&error); /* FIXME don't raise here */
5320 str = mono_string_chars (o);
5322 while (text < end) {
5323 *str++ = g_utf8_get_char (text);
5324 text = g_utf8_next_char (text);
5331 * mono_string_new_wrapper:
5332 * @text: pointer to utf8 characters.
5334 * Helper function to create a string object from @text in the current domain.
5337 mono_string_new_wrapper (const char *text)
5339 MONO_REQ_GC_UNSAFE_MODE;
5341 MonoDomain *domain = mono_domain_get ();
5344 return mono_string_new (domain, text);
5351 * @class: the class of the value
5352 * @value: a pointer to the unboxed data
5354 * Returns: A newly created object which contains @value.
5357 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5359 MONO_REQ_GC_UNSAFE_MODE;
5366 g_assert (klass->valuetype);
5367 if (mono_class_is_nullable (klass))
5368 return mono_nullable_box ((guint8 *)value, klass);
5370 vtable = mono_class_vtable (domain, klass);
5373 size = mono_class_instance_size (klass);
5374 res = mono_object_new_alloc_specific_checked (vtable, &error);
5375 mono_error_raise_exception (&error); /* FIXME don't raise here */
5377 size = size - sizeof (MonoObject);
5380 g_assert (size == mono_class_value_size (klass, NULL));
5381 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5383 #if NO_UNALIGNED_ACCESS
5384 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5388 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5391 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5394 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5397 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5400 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5404 if (klass->has_finalize)
5405 mono_object_register_finalizer (res);
5411 * @dest: destination pointer
5412 * @src: source pointer
5413 * @klass: a valuetype class
5415 * Copy a valuetype from @src to @dest. This function must be used
5416 * when @klass contains references fields.
5419 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5421 MONO_REQ_GC_UNSAFE_MODE;
5423 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5427 * mono_value_copy_array:
5428 * @dest: destination array
5429 * @dest_idx: index in the @dest array
5430 * @src: source pointer
5431 * @count: number of items
5433 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5434 * This function must be used when @klass contains references fields.
5435 * Overlap is handled.
5438 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5440 MONO_REQ_GC_UNSAFE_MODE;
5442 int size = mono_array_element_size (dest->obj.vtable->klass);
5443 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5444 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5445 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5449 * mono_object_get_domain:
5450 * @obj: object to query
5452 * Returns: the MonoDomain where the object is hosted
5455 mono_object_get_domain (MonoObject *obj)
5457 MONO_REQ_GC_UNSAFE_MODE;
5459 return mono_object_domain (obj);
5463 * mono_object_get_class:
5464 * @obj: object to query
5466 * Returns: the MonOClass of the object.
5469 mono_object_get_class (MonoObject *obj)
5471 MONO_REQ_GC_UNSAFE_MODE;
5473 return mono_object_class (obj);
5476 * mono_object_get_size:
5477 * @o: object to query
5479 * Returns: the size, in bytes, of @o
5482 mono_object_get_size (MonoObject* o)
5484 MONO_REQ_GC_UNSAFE_MODE;
5486 MonoClass* klass = mono_object_class (o);
5487 if (klass == mono_defaults.string_class) {
5488 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5489 } else if (o->vtable->rank) {
5490 MonoArray *array = (MonoArray*)o;
5491 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5492 if (array->bounds) {
5495 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5499 return mono_class_instance_size (klass);
5504 * mono_object_unbox:
5505 * @obj: object to unbox
5507 * Returns: a pointer to the start of the valuetype boxed in this
5510 * This method will assert if the object passed is not a valuetype.
5513 mono_object_unbox (MonoObject *obj)
5515 MONO_REQ_GC_UNSAFE_MODE;
5517 /* add assert for valuetypes? */
5518 g_assert (obj->vtable->klass->valuetype);
5519 return ((char*)obj) + sizeof (MonoObject);
5523 * mono_object_isinst:
5525 * @klass: a pointer to a class
5527 * Returns: @obj if @obj is derived from @klass
5530 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5532 MONO_REQ_GC_UNSAFE_MODE;
5535 mono_class_init (klass);
5537 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5538 return mono_object_isinst_mbyref (obj, klass);
5543 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5547 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5549 MONO_REQ_GC_UNSAFE_MODE;
5558 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5559 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5563 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5564 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5567 MonoClass *oklass = vt->klass;
5568 if (mono_class_is_transparent_proxy (oklass))
5569 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5571 mono_class_setup_supertypes (klass);
5572 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5575 #ifndef DISABLE_REMOTING
5576 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5578 MonoDomain *domain = mono_domain_get ();
5580 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5581 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5582 MonoMethod *im = NULL;
5585 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5587 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5588 im = mono_object_get_virtual_method (rp, im);
5591 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5594 res = mono_runtime_invoke (im, rp, pa, NULL);
5596 if (*(MonoBoolean *) mono_object_unbox(res)) {
5597 /* Update the vtable of the remote type, so it can safely cast to this new type */
5598 mono_upgrade_remote_class (domain, obj, klass);
5602 #endif /* DISABLE_REMOTING */
5607 * mono_object_castclass_mbyref:
5609 * @klass: a pointer to a class
5611 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5614 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5616 MONO_REQ_GC_UNSAFE_MODE;
5618 if (!obj) return NULL;
5619 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5621 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5623 "InvalidCastException"));
5628 MonoDomain *orig_domain;
5634 str_lookup (MonoDomain *domain, gpointer user_data)
5636 MONO_REQ_GC_UNSAFE_MODE;
5638 LDStrInfo *info = (LDStrInfo *)user_data;
5639 if (info->res || domain == info->orig_domain)
5641 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5645 mono_string_get_pinned (MonoString *str, MonoError *error)
5647 MONO_REQ_GC_UNSAFE_MODE;
5649 mono_error_init (error);
5651 /* We only need to make a pinned version of a string if this is a moving GC */
5652 if (!mono_gc_is_moving ())
5656 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5657 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5659 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5660 news->length = mono_string_length (str);
5662 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5668 mono_string_is_interned_lookup (MonoString *str, int insert)
5670 MONO_REQ_GC_UNSAFE_MODE;
5673 MonoGHashTable *ldstr_table;
5674 MonoString *s, *res;
5677 domain = ((MonoObject *)str)->vtable->domain;
5678 ldstr_table = domain->ldstr_table;
5680 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5686 /* Allocate outside the lock */
5688 s = mono_string_get_pinned (str, &error);
5689 mono_error_raise_exception (&error); /* FIXME don't raise here */
5692 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5697 mono_g_hash_table_insert (ldstr_table, s, s);
5702 LDStrInfo ldstr_info;
5703 ldstr_info.orig_domain = domain;
5704 ldstr_info.ins = str;
5705 ldstr_info.res = NULL;
5707 mono_domain_foreach (str_lookup, &ldstr_info);
5708 if (ldstr_info.res) {
5710 * the string was already interned in some other domain:
5711 * intern it in the current one as well.
5713 mono_g_hash_table_insert (ldstr_table, str, str);
5723 * mono_string_is_interned:
5724 * @o: String to probe
5726 * Returns whether the string has been interned.
5729 mono_string_is_interned (MonoString *o)
5731 MONO_REQ_GC_UNSAFE_MODE;
5733 return mono_string_is_interned_lookup (o, FALSE);
5737 * mono_string_intern:
5738 * @o: String to intern
5740 * Interns the string passed.
5741 * Returns: The interned string.
5744 mono_string_intern (MonoString *str)
5746 MONO_REQ_GC_UNSAFE_MODE;
5748 return mono_string_is_interned_lookup (str, TRUE);
5753 * @domain: the domain where the string will be used.
5754 * @image: a metadata context
5755 * @idx: index into the user string table.
5757 * Implementation for the ldstr opcode.
5758 * Returns: a loaded string from the @image/@idx combination.
5761 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5763 MONO_REQ_GC_UNSAFE_MODE;
5765 if (image->dynamic) {
5766 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5769 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5770 return NULL; /*FIXME we should probably be raising an exception here*/
5771 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5776 * mono_ldstr_metadata_sig
5777 * @domain: the domain for the string
5778 * @sig: the signature of a metadata string
5780 * Returns: a MonoString for a string stored in the metadata
5783 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5785 MONO_REQ_GC_UNSAFE_MODE;
5788 const char *str = sig;
5789 MonoString *o, *interned;
5792 len2 = mono_metadata_decode_blob_size (str, &str);
5795 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5796 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5799 guint16 *p2 = (guint16*)mono_string_chars (o);
5800 for (i = 0; i < len2; ++i) {
5801 *p2 = GUINT16_FROM_LE (*p2);
5807 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5810 return interned; /* o will get garbage collected */
5812 o = mono_string_get_pinned (o, &error);
5813 mono_error_raise_exception (&error); /* FIXME don't raise here */
5816 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5818 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5828 * mono_string_to_utf8:
5829 * @s: a System.String
5831 * Returns the UTF8 representation for @s.
5832 * The resulting buffer needs to be freed with mono_free().
5834 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5837 mono_string_to_utf8 (MonoString *s)
5839 MONO_REQ_GC_UNSAFE_MODE;
5842 char *result = mono_string_to_utf8_checked (s, &error);
5844 if (!mono_error_ok (&error))
5845 mono_error_raise_exception (&error);
5850 * mono_string_to_utf8_checked:
5851 * @s: a System.String
5852 * @error: a MonoError.
5854 * Converts a MonoString to its UTF8 representation. May fail; check
5855 * @error to determine whether the conversion was successful.
5856 * The resulting buffer should be freed with mono_free().
5859 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5861 MONO_REQ_GC_UNSAFE_MODE;
5865 GError *gerror = NULL;
5867 mono_error_init (error);
5873 return g_strdup ("");
5875 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5877 mono_error_set_argument (error, "string", "%s", gerror->message);
5878 g_error_free (gerror);
5881 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5882 if (s->length > written) {
5883 /* allocate the total length and copy the part of the string that has been converted */
5884 char *as2 = (char *)g_malloc0 (s->length);
5885 memcpy (as2, as, written);
5894 * mono_string_to_utf8_ignore:
5897 * Converts a MonoString to its UTF8 representation. Will ignore
5898 * invalid surrogate pairs.
5899 * The resulting buffer should be freed with mono_free().
5903 mono_string_to_utf8_ignore (MonoString *s)
5905 MONO_REQ_GC_UNSAFE_MODE;
5914 return g_strdup ("");
5916 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5918 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5919 if (s->length > written) {
5920 /* allocate the total length and copy the part of the string that has been converted */
5921 char *as2 = (char *)g_malloc0 (s->length);
5922 memcpy (as2, as, written);
5931 * mono_string_to_utf8_image_ignore:
5932 * @s: a System.String
5934 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5937 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5939 MONO_REQ_GC_UNSAFE_MODE;
5941 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5945 * mono_string_to_utf8_mp_ignore:
5946 * @s: a System.String
5948 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5951 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5953 MONO_REQ_GC_UNSAFE_MODE;
5955 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5960 * mono_string_to_utf16:
5963 * Return an null-terminated array of the utf-16 chars
5964 * contained in @s. The result must be freed with g_free().
5965 * This is a temporary helper until our string implementation
5966 * is reworked to always include the null terminating char.
5969 mono_string_to_utf16 (MonoString *s)
5971 MONO_REQ_GC_UNSAFE_MODE;
5978 as = (char *)g_malloc ((s->length * 2) + 2);
5979 as [(s->length * 2)] = '\0';
5980 as [(s->length * 2) + 1] = '\0';
5983 return (gunichar2 *)(as);
5986 memcpy (as, mono_string_chars(s), s->length * 2);
5987 return (gunichar2 *)(as);
5991 * mono_string_to_utf32:
5994 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5995 * contained in @s. The result must be freed with g_free().
5998 mono_string_to_utf32 (MonoString *s)
6000 MONO_REQ_GC_UNSAFE_MODE;
6002 mono_unichar4 *utf32_output = NULL;
6003 GError *error = NULL;
6004 glong items_written;
6009 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6012 g_error_free (error);
6014 return utf32_output;
6018 * mono_string_from_utf16:
6019 * @data: the UTF16 string (LPWSTR) to convert
6021 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6023 * Returns: a MonoString.
6026 mono_string_from_utf16 (gunichar2 *data)
6028 MONO_REQ_GC_UNSAFE_MODE;
6030 MonoDomain *domain = mono_domain_get ();
6036 while (data [len]) len++;
6038 return mono_string_new_utf16 (domain, data, len);
6042 * mono_string_from_utf32:
6043 * @data: the UTF32 string (LPWSTR) to convert
6045 * Converts a UTF32 (UCS-4)to a MonoString.
6047 * Returns: a MonoString.
6050 mono_string_from_utf32 (mono_unichar4 *data)
6052 MONO_REQ_GC_UNSAFE_MODE;
6054 MonoString* result = NULL;
6055 mono_unichar2 *utf16_output = NULL;
6056 GError *error = NULL;
6057 glong items_written;
6063 while (data [len]) len++;
6065 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6068 g_error_free (error);
6070 result = mono_string_from_utf16 (utf16_output);
6071 g_free (utf16_output);
6076 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6078 MONO_REQ_GC_UNSAFE_MODE;
6085 r = mono_string_to_utf8_ignore (s);
6087 r = mono_string_to_utf8_checked (s, error);
6088 if (!mono_error_ok (error))
6095 len = strlen (r) + 1;
6097 mp_s = (char *)mono_mempool_alloc (mp, len);
6099 mp_s = (char *)mono_image_alloc (image, len);
6101 memcpy (mp_s, r, len);
6109 * mono_string_to_utf8_image:
6110 * @s: a System.String
6112 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6115 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6117 MONO_REQ_GC_UNSAFE_MODE;
6119 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6123 * mono_string_to_utf8_mp:
6124 * @s: a System.String
6126 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6129 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6131 MONO_REQ_GC_UNSAFE_MODE;
6133 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6137 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6140 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6142 eh_callbacks = *cbs;
6145 MonoRuntimeExceptionHandlingCallbacks *
6146 mono_get_eh_callbacks (void)
6148 return &eh_callbacks;
6152 * mono_raise_exception:
6153 * @ex: exception object
6155 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6158 mono_raise_exception (MonoException *ex)
6160 MONO_REQ_GC_UNSAFE_MODE;
6163 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6164 * that will cause gcc to omit the function epilog, causing problems when
6165 * the JIT tries to walk the stack, since the return address on the stack
6166 * will point into the next function in the executable, not this one.
6168 eh_callbacks.mono_raise_exception (ex);
6172 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6174 MONO_REQ_GC_UNSAFE_MODE;
6176 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6180 * mono_wait_handle_new:
6181 * @domain: Domain where the object will be created
6182 * @handle: Handle for the wait handle
6184 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6187 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6189 MONO_REQ_GC_UNSAFE_MODE;
6191 MonoWaitHandle *res;
6192 gpointer params [1];
6193 static MonoMethod *handle_set;
6195 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6197 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6199 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6201 params [0] = &handle;
6202 mono_runtime_invoke (handle_set, res, params, NULL);
6208 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6210 MONO_REQ_GC_UNSAFE_MODE;
6212 static MonoClassField *f_os_handle;
6213 static MonoClassField *f_safe_handle;
6215 if (!f_os_handle && !f_safe_handle) {
6216 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6217 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6222 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6226 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6233 mono_runtime_capture_context (MonoDomain *domain)
6235 MONO_REQ_GC_UNSAFE_MODE;
6237 RuntimeInvokeFunction runtime_invoke;
6239 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6240 MonoMethod *method = mono_get_context_capture_method ();
6241 MonoMethod *wrapper;
6244 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6245 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6246 domain->capture_context_method = mono_compile_method (method);
6249 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6251 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6254 * mono_async_result_new:
6255 * @domain:domain where the object will be created.
6256 * @handle: wait handle.
6257 * @state: state to pass to AsyncResult
6258 * @data: C closure data.
6260 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6261 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6265 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6267 MONO_REQ_GC_UNSAFE_MODE;
6269 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6270 MonoObject *context = mono_runtime_capture_context (domain);
6271 /* we must capture the execution context from the original thread */
6273 MONO_OBJECT_SETREF (res, execution_context, context);
6274 /* note: result may be null if the flow is suppressed */
6277 res->data = (void **)data;
6278 MONO_OBJECT_SETREF (res, object_data, object_data);
6279 MONO_OBJECT_SETREF (res, async_state, state);
6281 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6283 res->sync_completed = FALSE;
6284 res->completed = FALSE;
6290 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6292 MONO_REQ_GC_UNSAFE_MODE;
6298 g_assert (ares->async_delegate);
6300 ac = (MonoAsyncCall*) ares->object_data;
6302 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6304 gpointer wait_event = NULL;
6306 ac->msg->exc = NULL;
6307 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6308 MONO_OBJECT_SETREF (ac, res, res);
6310 mono_monitor_enter ((MonoObject*) ares);
6311 ares->completed = 1;
6313 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6314 mono_monitor_exit ((MonoObject*) ares);
6316 if (wait_event != NULL)
6317 SetEvent (wait_event);
6319 if (ac->cb_method) {
6320 /* we swallow the excepton as it is the behavior on .NET */
6321 MonoObject *exc = NULL;
6322 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6324 mono_unhandled_exception (exc);
6332 mono_message_init (MonoDomain *domain,
6333 MonoMethodMessage *this_obj,
6334 MonoReflectionMethod *method,
6335 MonoArray *out_args)
6337 MONO_REQ_GC_UNSAFE_MODE;
6339 static MonoClass *object_array_klass;
6340 static MonoClass *byte_array_klass;
6341 static MonoClass *string_array_klass;
6343 MonoMethodSignature *sig = mono_method_signature (method->method);
6350 if (!object_array_klass) {
6353 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6355 byte_array_klass = klass;
6357 klass = mono_array_class_get (mono_defaults.string_class, 1);
6359 string_array_klass = klass;
6361 klass = mono_array_class_get (mono_defaults.object_class, 1);
6364 mono_atomic_store_release (&object_array_klass, klass);
6367 MONO_OBJECT_SETREF (this_obj, method, method);
6369 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6370 mono_error_raise_exception (&error); /* FIXME don't raise here */
6372 MONO_OBJECT_SETREF (this_obj, args, arr);
6374 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6375 mono_error_raise_exception (&error); /* FIXME don't raise here */
6377 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6379 this_obj->async_result = NULL;
6380 this_obj->call_type = CallType_Sync;
6382 names = g_new (char *, sig->param_count);
6383 mono_method_get_param_names (method->method, (const char **) names);
6385 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6386 mono_error_raise_exception (&error); /* FIXME don't raise here */
6388 MONO_OBJECT_SETREF (this_obj, names, arr);
6390 for (i = 0; i < sig->param_count; i++) {
6391 name = mono_string_new (domain, names [i]);
6392 mono_array_setref (this_obj->names, i, name);
6396 for (i = 0, j = 0; i < sig->param_count; i++) {
6397 if (sig->params [i]->byref) {
6399 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6400 mono_array_setref (this_obj->args, i, arg);
6404 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6408 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6411 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6415 #ifndef DISABLE_REMOTING
6417 * mono_remoting_invoke:
6418 * @real_proxy: pointer to a RealProxy object
6419 * @msg: The MonoMethodMessage to execute
6420 * @exc: used to store exceptions
6421 * @out_args: used to store output arguments
6423 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6424 * IMessage interface and it is not trivial to extract results from there. So
6425 * we call an helper method PrivateInvoke instead of calling
6426 * RealProxy::Invoke() directly.
6428 * Returns: the result object.
6431 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6432 MonoObject **exc, MonoArray **out_args)
6434 MONO_REQ_GC_UNSAFE_MODE;
6436 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6439 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6442 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6444 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6445 real_proxy->vtable->domain->private_invoke_method = im;
6448 pa [0] = real_proxy;
6453 return mono_runtime_invoke (im, NULL, pa, exc);
6458 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6459 MonoObject **exc, MonoArray **out_args)
6461 MONO_REQ_GC_UNSAFE_MODE;
6463 static MonoClass *object_array_klass;
6467 MonoMethodSignature *sig;
6470 int i, j, outarg_count = 0;
6472 #ifndef DISABLE_REMOTING
6473 if (target && mono_object_is_transparent_proxy (target)) {
6474 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6475 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6476 target = tp->rp->unwrapped_server;
6478 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6483 domain = mono_domain_get ();
6484 method = msg->method->method;
6485 sig = mono_method_signature (method);
6487 for (i = 0; i < sig->param_count; i++) {
6488 if (sig->params [i]->byref)
6492 if (!object_array_klass) {
6495 klass = mono_array_class_get (mono_defaults.object_class, 1);
6498 mono_memory_barrier ();
6499 object_array_klass = klass;
6502 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6503 mono_error_raise_exception (&error); /* FIXME don't raise here */
6505 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6508 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6510 for (i = 0, j = 0; i < sig->param_count; i++) {
6511 if (sig->params [i]->byref) {
6513 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6514 mono_array_setref (*out_args, j, arg);
6523 * mono_object_to_string:
6525 * @exc: Any exception thrown by ToString (). May be NULL.
6527 * Returns: the result of calling ToString () on an object.
6530 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6532 MONO_REQ_GC_UNSAFE_MODE;
6534 static MonoMethod *to_string = NULL;
6541 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6543 method = mono_object_get_virtual_method (obj, to_string);
6545 // Unbox value type if needed
6546 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6547 target = mono_object_unbox (obj);
6550 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6554 * mono_print_unhandled_exception:
6555 * @exc: The exception
6557 * Prints the unhandled exception.
6560 mono_print_unhandled_exception (MonoObject *exc)
6562 MONO_REQ_GC_UNSAFE_MODE;
6565 char *message = (char*)"";
6566 gboolean free_message = FALSE;
6569 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6570 message = g_strdup ("OutOfMemoryException");
6571 free_message = TRUE;
6572 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6573 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6574 free_message = TRUE;
6577 if (((MonoException*)exc)->native_trace_ips) {
6578 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6579 free_message = TRUE;
6581 MonoObject *other_exc = NULL;
6582 str = mono_object_to_string (exc, &other_exc);
6584 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6585 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6587 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6588 original_backtrace, nested_backtrace);
6590 g_free (original_backtrace);
6591 g_free (nested_backtrace);
6592 free_message = TRUE;
6594 message = mono_string_to_utf8_checked (str, &error);
6595 if (!mono_error_ok (&error)) {
6596 mono_error_cleanup (&error);
6597 message = (char *) "";
6599 free_message = TRUE;
6606 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6607 * exc->vtable->klass->name, message);
6609 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6616 * mono_delegate_ctor:
6617 * @this: pointer to an uninitialized delegate object
6618 * @target: target object
6619 * @addr: pointer to native code
6622 * Initialize a delegate and sets a specific method, not the one
6623 * associated with addr. This is useful when sharing generic code.
6624 * In that case addr will most probably not be associated with the
6625 * correct instantiation of the method.
6628 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6630 MONO_REQ_GC_UNSAFE_MODE;
6632 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6634 g_assert (this_obj);
6637 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6640 delegate->method = method;
6642 mono_stats.delegate_creations++;
6644 #ifndef DISABLE_REMOTING
6645 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6647 method = mono_marshal_get_remoting_invoke (method);
6648 delegate->method_ptr = mono_compile_method (method);
6649 MONO_OBJECT_SETREF (delegate, target, target);
6653 delegate->method_ptr = addr;
6654 MONO_OBJECT_SETREF (delegate, target, target);
6657 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6658 if (callbacks.init_delegate)
6659 callbacks.init_delegate (delegate);
6663 * mono_delegate_ctor:
6664 * @this: pointer to an uninitialized delegate object
6665 * @target: target object
6666 * @addr: pointer to native code
6668 * This is used to initialize a delegate.
6671 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6673 MONO_REQ_GC_UNSAFE_MODE;
6675 MonoDomain *domain = mono_domain_get ();
6677 MonoMethod *method = NULL;
6681 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6683 if (!ji && domain != mono_get_root_domain ())
6684 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6686 method = mono_jit_info_get_method (ji);
6687 g_assert (!method->klass->generic_container);
6690 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6694 * mono_method_call_message_new:
6695 * @method: method to encapsulate
6696 * @params: parameters to the method
6697 * @invoke: optional, delegate invoke.
6698 * @cb: async callback delegate.
6699 * @state: state passed to the async callback.
6701 * Translates arguments pointers into a MonoMethodMessage.
6704 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6705 MonoDelegate **cb, MonoObject **state)
6707 MONO_REQ_GC_UNSAFE_MODE;
6709 MonoDomain *domain = mono_domain_get ();
6710 MonoMethodSignature *sig = mono_method_signature (method);
6711 MonoMethodMessage *msg;
6714 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6717 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6718 count = sig->param_count - 2;
6720 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6721 count = sig->param_count;
6724 for (i = 0; i < count; i++) {
6729 if (sig->params [i]->byref)
6730 vpos = *((gpointer *)params [i]);
6734 klass = mono_class_from_mono_type (sig->params [i]);
6736 if (klass->valuetype)
6737 arg = mono_value_box (domain, klass, vpos);
6739 arg = *((MonoObject **)vpos);
6741 mono_array_setref (msg->args, i, arg);
6744 if (cb != NULL && state != NULL) {
6745 *cb = *((MonoDelegate **)params [i]);
6747 *state = *((MonoObject **)params [i]);
6754 * mono_method_return_message_restore:
6756 * Restore results from message based processing back to arguments pointers
6759 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6761 MONO_REQ_GC_UNSAFE_MODE;
6763 MonoMethodSignature *sig = mono_method_signature (method);
6764 int i, j, type, size, out_len;
6766 if (out_args == NULL)
6768 out_len = mono_array_length (out_args);
6772 for (i = 0, j = 0; i < sig->param_count; i++) {
6773 MonoType *pt = sig->params [i];
6778 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6780 arg = (char *)mono_array_get (out_args, gpointer, j);
6783 g_assert (type != MONO_TYPE_VOID);
6785 if (MONO_TYPE_IS_REFERENCE (pt)) {
6786 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6789 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6790 size = mono_class_value_size (klass, NULL);
6791 if (klass->has_references)
6792 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6794 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6796 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6797 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6806 #ifndef DISABLE_REMOTING
6809 * mono_load_remote_field:
6810 * @this: pointer to an object
6811 * @klass: klass of the object containing @field
6812 * @field: the field to load
6813 * @res: a storage to store the result
6815 * This method is called by the runtime on attempts to load fields of
6816 * transparent proxy objects. @this points to such TP, @klass is the class of
6817 * the object containing @field. @res is a storage location which can be
6818 * used to store the result.
6820 * Returns: an address pointing to the value of field.
6823 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6825 MONO_REQ_GC_UNSAFE_MODE;
6827 static MonoMethod *getter = NULL;
6828 MonoDomain *domain = mono_domain_get ();
6829 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6830 MonoClass *field_class;
6831 MonoMethodMessage *msg;
6832 MonoArray *out_args;
6836 g_assert (mono_object_is_transparent_proxy (this_obj));
6837 g_assert (res != NULL);
6839 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6840 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6845 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6847 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6850 field_class = mono_class_from_mono_type (field->type);
6852 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6853 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6854 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6856 full_name = mono_type_get_full_name (klass);
6857 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6858 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6861 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6863 if (exc) mono_raise_exception ((MonoException *)exc);
6865 if (mono_array_length (out_args) == 0)
6868 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6870 if (field_class->valuetype) {
6871 return ((char *)*res) + sizeof (MonoObject);
6877 * mono_load_remote_field_new:
6882 * Missing documentation.
6885 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6887 MONO_REQ_GC_UNSAFE_MODE;
6889 static MonoMethod *getter = NULL;
6890 MonoDomain *domain = mono_domain_get ();
6891 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6892 MonoClass *field_class;
6893 MonoMethodMessage *msg;
6894 MonoArray *out_args;
6895 MonoObject *exc, *res;
6898 g_assert (mono_object_is_transparent_proxy (this_obj));
6900 field_class = mono_class_from_mono_type (field->type);
6902 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6904 if (field_class->valuetype) {
6905 res = mono_object_new (domain, field_class);
6906 val = ((gchar *) res) + sizeof (MonoObject);
6910 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6915 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6917 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6920 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6921 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6923 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6925 full_name = mono_type_get_full_name (klass);
6926 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6927 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6930 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6932 if (exc) mono_raise_exception ((MonoException *)exc);
6934 if (mono_array_length (out_args) == 0)
6937 res = mono_array_get (out_args, MonoObject *, 0);
6943 * mono_store_remote_field:
6944 * @this_obj: pointer to an object
6945 * @klass: klass of the object containing @field
6946 * @field: the field to load
6947 * @val: the value/object to store
6949 * This method is called by the runtime on attempts to store fields of
6950 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6951 * the object containing @field. @val is the new value to store in @field.
6954 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6956 MONO_REQ_GC_UNSAFE_MODE;
6958 static MonoMethod *setter = NULL;
6959 MonoDomain *domain = mono_domain_get ();
6960 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6961 MonoClass *field_class;
6962 MonoMethodMessage *msg;
6963 MonoArray *out_args;
6968 g_assert (mono_object_is_transparent_proxy (this_obj));
6970 field_class = mono_class_from_mono_type (field->type);
6972 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6973 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6974 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6979 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6981 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6984 if (field_class->valuetype)
6985 arg = mono_value_box (domain, field_class, val);
6987 arg = *((MonoObject **)val);
6990 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6991 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6993 full_name = mono_type_get_full_name (klass);
6994 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6995 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6996 mono_array_setref (msg->args, 2, arg);
6999 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7001 if (exc) mono_raise_exception ((MonoException *)exc);
7005 * mono_store_remote_field_new:
7011 * Missing documentation
7014 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7016 MONO_REQ_GC_UNSAFE_MODE;
7018 static MonoMethod *setter = NULL;
7019 MonoDomain *domain = mono_domain_get ();
7020 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7021 MonoClass *field_class;
7022 MonoMethodMessage *msg;
7023 MonoArray *out_args;
7027 g_assert (mono_object_is_transparent_proxy (this_obj));
7029 field_class = mono_class_from_mono_type (field->type);
7031 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7032 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7033 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7038 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7040 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7043 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7044 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7046 full_name = mono_type_get_full_name (klass);
7047 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7048 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7049 mono_array_setref (msg->args, 2, arg);
7052 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7054 if (exc) mono_raise_exception ((MonoException *)exc);
7059 * mono_create_ftnptr:
7061 * Given a function address, create a function descriptor for it.
7062 * This is only needed on some platforms.
7065 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7067 return callbacks.create_ftnptr (domain, addr);
7071 * mono_get_addr_from_ftnptr:
7073 * Given a pointer to a function descriptor, return the function address.
7074 * This is only needed on some platforms.
7077 mono_get_addr_from_ftnptr (gpointer descr)
7079 return callbacks.get_addr_from_ftnptr (descr);
7083 * mono_string_chars:
7086 * Returns a pointer to the UCS16 characters stored in the MonoString
7089 mono_string_chars (MonoString *s)
7091 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7097 * mono_string_length:
7100 * Returns the lenght in characters of the string
7103 mono_string_length (MonoString *s)
7105 MONO_REQ_GC_UNSAFE_MODE;
7111 * mono_array_length:
7112 * @array: a MonoArray*
7114 * Returns the total number of elements in the array. This works for
7115 * both vectors and multidimensional arrays.
7118 mono_array_length (MonoArray *array)
7120 MONO_REQ_GC_UNSAFE_MODE;
7122 return array->max_length;
7126 * mono_array_addr_with_size:
7127 * @array: a MonoArray*
7128 * @size: size of the array elements
7129 * @idx: index into the array
7131 * Returns the address of the @idx element in the array.
7134 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7136 MONO_REQ_GC_UNSAFE_MODE;
7138 return ((char*)(array)->vector) + size * idx;
7143 mono_glist_to_array (GList *list, MonoClass *eclass)
7145 MonoDomain *domain = mono_domain_get ();
7152 len = g_list_length (list);
7153 res = mono_array_new (domain, eclass, len);
7155 for (i = 0; list; list = list->next, i++)
7156 mono_array_set (res, gpointer, i, list->data);