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/metadata/reflection-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include <mono/utils/checked-build.h>
47 #include <mono/utils/mono-threads.h>
48 #include "cominterop.h"
51 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
54 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
57 free_main_args (void);
60 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
63 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
64 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
65 static mono_mutex_t ldstr_section;
68 mono_runtime_object_init (MonoObject *this_obj)
70 MONO_REQ_GC_UNSAFE_MODE;
72 MonoMethod *method = NULL;
73 MonoClass *klass = this_obj->vtable->klass;
75 method = mono_class_get_method_from_name (klass, ".ctor", 0);
77 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
79 if (method->klass->valuetype)
80 this_obj = (MonoObject *)mono_object_unbox (this_obj);
81 mono_runtime_invoke (method, this_obj, NULL, NULL);
84 /* The pseudo algorithm for type initialization from the spec
85 Note it doesn't say anything about domains - only threads.
87 2. If the type is initialized you are done.
88 2.1. If the type is not yet initialized, try to take an
90 2.2. If successful, record this thread as responsible for
91 initializing the type and proceed to step 2.3.
92 2.2.1. If not, see whether this thread or any thread
93 waiting for this thread to complete already holds the lock.
94 2.2.2. If so, return since blocking would create a deadlock. This thread
95 will now see an incompletely initialized state for the type,
96 but no deadlock will arise.
97 2.2.3 If not, block until the type is initialized then return.
98 2.3 Initialize the parent type and then all interfaces implemented
100 2.4 Execute the type initialization code for this type.
101 2.5 Mark the type as initialized, release the initialization lock,
102 awaken any threads waiting for this type to be initialized,
109 MonoNativeThreadId initializing_tid;
110 guint32 waiting_count;
112 MonoCoopMutex initialization_section;
113 } TypeInitializationLock;
115 /* for locking access to type_initialization_hash and blocked_thread_hash */
116 static MonoCoopMutex type_initialization_section;
119 mono_type_initialization_lock (void)
121 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
122 mono_coop_mutex_lock (&type_initialization_section);
126 mono_type_initialization_unlock (void)
128 mono_coop_mutex_unlock (&type_initialization_section);
132 mono_type_init_lock (TypeInitializationLock *lock)
134 MONO_REQ_GC_NEUTRAL_MODE;
136 mono_coop_mutex_lock (&lock->initialization_section);
140 mono_type_init_unlock (TypeInitializationLock *lock)
142 mono_coop_mutex_unlock (&lock->initialization_section);
145 /* from vtable to lock */
146 static GHashTable *type_initialization_hash;
148 /* from thread id to thread id being waited on */
149 static GHashTable *blocked_thread_hash;
152 static MonoThread *main_thread;
154 /* Functions supplied by the runtime */
155 static MonoRuntimeCallbacks callbacks;
158 * mono_thread_set_main:
159 * @thread: thread to set as the main thread
161 * This function can be used to instruct the runtime to treat @thread
162 * as the main thread, ie, the thread that would normally execute the Main()
163 * method. This basically means that at the end of @thread, the runtime will
164 * wait for the existing foreground threads to quit and other such details.
167 mono_thread_set_main (MonoThread *thread)
169 MONO_REQ_GC_UNSAFE_MODE;
171 static gboolean registered = FALSE;
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
178 main_thread = thread;
182 mono_thread_get_main (void)
184 MONO_REQ_GC_UNSAFE_MODE;
190 mono_type_initialization_init (void)
192 mono_coop_mutex_init_recursive (&type_initialization_section);
193 type_initialization_hash = g_hash_table_new (NULL, NULL);
194 blocked_thread_hash = g_hash_table_new (NULL, NULL);
195 mono_os_mutex_init_recursive (&ldstr_section);
199 mono_type_initialization_cleanup (void)
202 /* This is causing race conditions with
203 * mono_release_type_locks
205 mono_coop_mutex_destroy (&type_initialization_section);
206 g_hash_table_destroy (type_initialization_hash);
207 type_initialization_hash = NULL;
209 mono_os_mutex_destroy (&ldstr_section);
210 g_hash_table_destroy (blocked_thread_hash);
211 blocked_thread_hash = NULL;
217 * get_type_init_exception_for_vtable:
219 * Return the stored type initialization exception for VTABLE.
221 static MonoException*
222 get_type_init_exception_for_vtable (MonoVTable *vtable)
224 MONO_REQ_GC_UNSAFE_MODE;
226 MonoDomain *domain = vtable->domain;
227 MonoClass *klass = vtable->klass;
231 if (!vtable->init_failed)
232 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
235 * If the initializing thread was rudely aborted, the exception is not stored
239 mono_domain_lock (domain);
240 if (domain->type_init_exception_hash)
241 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
242 mono_domain_unlock (domain);
245 if (klass->name_space && *klass->name_space)
246 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
248 full_name = g_strdup (klass->name);
249 ex = mono_get_exception_type_initialization (full_name, NULL);
256 * mono_runtime_class_init:
257 * @vtable: vtable that needs to be initialized
259 * This routine calls the class constructor for @vtable.
262 mono_runtime_class_init (MonoVTable *vtable)
264 MONO_REQ_GC_UNSAFE_MODE;
266 mono_runtime_class_init_full (vtable, TRUE);
270 * mono_runtime_class_init_full:
271 * @vtable that neeeds to be initialized
272 * @raise_exception is TRUE, exceptions are raised intead of returned
276 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
278 MONO_REQ_GC_UNSAFE_MODE;
281 MonoException *exc_to_throw;
282 MonoMethod *method = NULL;
285 MonoDomain *domain = vtable->domain;
286 TypeInitializationLock *lock;
287 MonoNativeThreadId tid;
288 int do_initialization = 0;
289 MonoDomain *last_domain = NULL;
291 if (vtable->initialized)
295 klass = vtable->klass;
297 if (!klass->image->checked_module_cctor) {
298 mono_image_check_for_module_cctor (klass->image);
299 if (klass->image->has_module_cctor) {
301 MonoClass *module_klass;
302 MonoVTable *module_vtable;
304 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
306 exc = mono_error_convert_to_exception (&error);
308 mono_raise_exception (exc);
312 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
315 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
320 method = mono_class_get_cctor (klass);
322 vtable->initialized = 1;
326 tid = mono_native_thread_id_get ();
328 mono_type_initialization_lock ();
329 /* double check... */
330 if (vtable->initialized) {
331 mono_type_initialization_unlock ();
334 if (vtable->init_failed) {
335 mono_type_initialization_unlock ();
337 /* The type initialization already failed once, rethrow the same exception */
339 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
340 return get_type_init_exception_for_vtable (vtable);
342 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
344 /* This thread will get to do the initialization */
345 if (mono_domain_get () != domain) {
346 /* Transfer into the target domain */
347 last_domain = mono_domain_get ();
348 if (!mono_domain_set (domain, FALSE)) {
349 vtable->initialized = 1;
350 mono_type_initialization_unlock ();
352 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
353 return mono_get_exception_appdomain_unloaded ();
356 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
357 mono_coop_mutex_init_recursive (&lock->initialization_section);
358 lock->initializing_tid = tid;
359 lock->waiting_count = 1;
361 /* grab the vtable lock while this thread still owns type_initialization_section */
362 /* This is why type_initialization_lock needs to enter blocking mode */
363 mono_type_init_lock (lock);
364 g_hash_table_insert (type_initialization_hash, vtable, lock);
365 do_initialization = 1;
368 TypeInitializationLock *pending_lock;
370 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
371 mono_type_initialization_unlock ();
374 /* see if the thread doing the initialization is already blocked on this thread */
375 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
376 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
377 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
378 if (!pending_lock->done) {
379 mono_type_initialization_unlock ();
382 /* the thread doing the initialization is blocked on this thread,
383 but on a lock that has already been freed. It just hasn't got
388 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
390 ++lock->waiting_count;
391 /* record the fact that we are waiting on the initializing thread */
392 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
394 mono_type_initialization_unlock ();
396 if (do_initialization) {
397 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
399 /* If the initialization failed, mark the class as unusable. */
400 /* Avoid infinite loops */
402 (klass->image == mono_defaults.corlib &&
403 !strcmp (klass->name_space, "System") &&
404 !strcmp (klass->name, "TypeInitializationException")))) {
405 vtable->init_failed = 1;
407 if (klass->name_space && *klass->name_space)
408 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
410 full_name = g_strdup (klass->name);
411 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
415 * Store the exception object so it could be thrown on subsequent
418 mono_domain_lock (domain);
419 if (!domain->type_init_exception_hash)
420 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");
421 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
422 mono_domain_unlock (domain);
426 mono_domain_set (last_domain, TRUE);
428 mono_type_init_unlock (lock);
430 /* this just blocks until the initializing thread is done */
431 mono_type_init_lock (lock);
432 mono_type_init_unlock (lock);
435 mono_type_initialization_lock ();
436 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
437 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
438 --lock->waiting_count;
439 if (lock->waiting_count == 0) {
440 mono_coop_mutex_destroy (&lock->initialization_section);
441 g_hash_table_remove (type_initialization_hash, vtable);
444 mono_memory_barrier ();
445 if (!vtable->init_failed)
446 vtable->initialized = 1;
447 mono_type_initialization_unlock ();
449 if (vtable->init_failed) {
450 /* Either we were the initializing thread or we waited for the initialization */
452 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
453 return get_type_init_exception_for_vtable (vtable);
459 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
461 MONO_REQ_GC_NEUTRAL_MODE;
463 MonoVTable *vtable = (MonoVTable*)key;
465 TypeInitializationLock *lock = (TypeInitializationLock*) value;
466 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
469 * Have to set this since it cannot be set by the normal code in
470 * mono_runtime_class_init (). In this case, the exception object is not stored,
471 * and get_type_init_exception_for_class () needs to be aware of this.
473 vtable->init_failed = 1;
474 mono_type_init_unlock (lock);
475 --lock->waiting_count;
476 if (lock->waiting_count == 0) {
477 mono_coop_mutex_destroy (&lock->initialization_section);
486 mono_release_type_locks (MonoInternalThread *thread)
488 MONO_REQ_GC_UNSAFE_MODE;
490 mono_type_initialization_lock ();
491 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
492 mono_type_initialization_unlock ();
496 default_trampoline (MonoMethod *method)
502 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
504 g_assert_not_reached ();
509 #ifndef DISABLE_REMOTING
512 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
514 g_error ("remoting not installed");
518 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
522 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
524 g_assert_not_reached ();
528 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
529 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
530 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
531 static MonoImtThunkBuilder imt_thunk_builder;
532 static gboolean always_build_imt_thunks;
534 #if (MONO_IMT_SIZE > 32)
535 #error "MONO_IMT_SIZE cannot be larger than 32"
539 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
541 memcpy (&callbacks, cbs, sizeof (*cbs));
544 MonoRuntimeCallbacks*
545 mono_get_runtime_callbacks (void)
551 mono_install_trampoline (MonoTrampoline func)
553 arch_create_jit_trampoline = func? func: default_trampoline;
557 mono_install_jump_trampoline (MonoJumpTrampoline func)
559 arch_create_jump_trampoline = func? func: default_jump_trampoline;
562 #ifndef DISABLE_REMOTING
564 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
566 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
571 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
573 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
577 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
578 imt_thunk_builder = func;
582 mono_set_always_build_imt_thunks (gboolean value)
584 always_build_imt_thunks = value;
587 static MonoCompileFunc default_mono_compile_method = NULL;
590 * mono_install_compile_method:
591 * @func: function to install
593 * This is a VM internal routine
596 mono_install_compile_method (MonoCompileFunc func)
598 default_mono_compile_method = func;
602 * mono_compile_method:
603 * @method: The method to compile.
605 * This JIT-compiles the method, and returns the pointer to the native code
609 mono_compile_method (MonoMethod *method)
611 MONO_REQ_GC_NEUTRAL_MODE
613 if (!default_mono_compile_method) {
614 g_error ("compile method called on uninitialized runtime");
617 return default_mono_compile_method (method);
621 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
623 MONO_REQ_GC_NEUTRAL_MODE
625 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
629 mono_runtime_create_delegate_trampoline (MonoClass *klass)
631 MONO_REQ_GC_NEUTRAL_MODE
633 return arch_create_delegate_trampoline (mono_domain_get (), klass);
636 static MonoFreeMethodFunc default_mono_free_method = NULL;
639 * mono_install_free_method:
640 * @func: pointer to the MonoFreeMethodFunc used to release a method
642 * This is an internal VM routine, it is used for the engines to
643 * register a handler to release the resources associated with a method.
645 * Methods are freed when no more references to the delegate that holds
649 mono_install_free_method (MonoFreeMethodFunc func)
651 default_mono_free_method = func;
655 * mono_runtime_free_method:
656 * @domain; domain where the method is hosted
657 * @method: method to release
659 * This routine is invoked to free the resources associated with
660 * a method that has been JIT compiled. This is used to discard
661 * methods that were used only temporarily (for example, used in marshalling)
665 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
667 MONO_REQ_GC_NEUTRAL_MODE
669 if (default_mono_free_method != NULL)
670 default_mono_free_method (domain, method);
672 mono_method_clear_object (domain, method);
674 mono_free_method (method);
678 * The vtables in the root appdomain are assumed to be reachable by other
679 * roots, and we don't use typed allocation in the other domains.
682 /* The sync block is no longer a GC pointer */
683 #define GC_HEADER_BITMAP (0)
685 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
688 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
690 MONO_REQ_GC_NEUTRAL_MODE;
692 MonoClassField *field;
698 max_size = mono_class_data_size (klass) / sizeof (gpointer);
700 max_size = klass->instance_size / sizeof (gpointer);
701 if (max_size > size) {
702 g_assert (offset <= 0);
703 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
708 /*An Ephemeron cannot be marked by sgen*/
709 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
711 memset (bitmap, 0, size / 8);
716 for (p = klass; p != NULL; p = p->parent) {
717 gpointer iter = NULL;
718 while ((field = mono_class_get_fields (p, &iter))) {
722 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
724 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
727 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
730 /* FIXME: should not happen, flag as type load error */
731 if (field->type->byref)
734 if (static_fields && field->offset == -1)
738 pos = field->offset / sizeof (gpointer);
741 type = mono_type_get_underlying_type (field->type);
742 switch (type->type) {
745 case MONO_TYPE_FNPTR:
747 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
752 if (klass->image != mono_defaults.corlib)
755 case MONO_TYPE_STRING:
756 case MONO_TYPE_SZARRAY:
757 case MONO_TYPE_CLASS:
758 case MONO_TYPE_OBJECT:
759 case MONO_TYPE_ARRAY:
760 g_assert ((field->offset % sizeof(gpointer)) == 0);
762 g_assert (pos < size || pos <= max_size);
763 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
764 *max_set = MAX (*max_set, pos);
766 case MONO_TYPE_GENERICINST:
767 if (!mono_type_generic_inst_is_valuetype (type)) {
768 g_assert ((field->offset % sizeof(gpointer)) == 0);
770 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
771 *max_set = MAX (*max_set, pos);
776 case MONO_TYPE_VALUETYPE: {
777 MonoClass *fclass = mono_class_from_mono_type (field->type);
778 if (fclass->has_references) {
779 /* remove the object header */
780 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
794 case MONO_TYPE_BOOLEAN:
798 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
809 * mono_class_compute_bitmap:
811 * Mono internal function to compute a bitmap of reference fields in a class.
814 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
816 MONO_REQ_GC_NEUTRAL_MODE;
818 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
823 * similar to the above, but sets the bits in the bitmap for any non-ref field
824 * and ignores static fields
827 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
829 MonoClassField *field;
834 max_size = class->instance_size / sizeof (gpointer);
835 if (max_size >= size) {
836 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
839 for (p = class; p != NULL; p = p->parent) {
840 gpointer iter = NULL;
841 while ((field = mono_class_get_fields (p, &iter))) {
844 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
846 /* FIXME: should not happen, flag as type load error */
847 if (field->type->byref)
850 pos = field->offset / sizeof (gpointer);
853 type = mono_type_get_underlying_type (field->type);
854 switch (type->type) {
855 #if SIZEOF_VOID_P == 8
859 case MONO_TYPE_FNPTR:
864 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
865 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
866 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
869 #if SIZEOF_VOID_P == 4
873 case MONO_TYPE_FNPTR:
878 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
879 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
880 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
886 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
887 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
888 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
891 case MONO_TYPE_BOOLEAN:
894 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
896 case MONO_TYPE_STRING:
897 case MONO_TYPE_SZARRAY:
898 case MONO_TYPE_CLASS:
899 case MONO_TYPE_OBJECT:
900 case MONO_TYPE_ARRAY:
902 case MONO_TYPE_GENERICINST:
903 if (!mono_type_generic_inst_is_valuetype (type)) {
908 case MONO_TYPE_VALUETYPE: {
909 MonoClass *fclass = mono_class_from_mono_type (field->type);
910 /* remove the object header */
911 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
915 g_assert_not_reached ();
924 * mono_class_insecure_overlapping:
925 * check if a class with explicit layout has references and non-references
926 * fields overlapping.
928 * Returns: TRUE if it is insecure to load the type.
931 mono_class_insecure_overlapping (MonoClass *klass)
935 gsize default_bitmap [4] = {0};
937 gsize default_nrbitmap [4] = {0};
938 int i, insecure = FALSE;
941 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
942 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
944 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
945 int idx = i % (sizeof (bitmap [0]) * 8);
946 if (bitmap [idx] & nrbitmap [idx]) {
951 if (bitmap != default_bitmap)
953 if (nrbitmap != default_nrbitmap)
956 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
964 ves_icall_string_alloc (int length)
967 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
968 mono_error_raise_exception (&error);
974 mono_class_compute_gc_descriptor (MonoClass *klass)
976 MONO_REQ_GC_NEUTRAL_MODE;
980 gsize default_bitmap [4] = {0};
981 static gboolean gcj_inited = FALSE;
986 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
987 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
990 mono_loader_unlock ();
994 mono_class_init (klass);
996 if (klass->gc_descr_inited)
999 klass->gc_descr_inited = TRUE;
1000 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1002 bitmap = default_bitmap;
1003 if (klass == mono_defaults.string_class) {
1004 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1005 } else if (klass->rank) {
1006 mono_class_compute_gc_descriptor (klass->element_class);
1007 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1009 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1010 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1011 class->name_space, class->name);*/
1013 /* remove the object header */
1014 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1015 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));
1016 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1017 class->name_space, class->name);*/
1018 if (bitmap != default_bitmap)
1022 /*static int count = 0;
1025 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1026 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1028 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1029 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1031 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1032 if (bitmap != default_bitmap)
1038 * field_is_special_static:
1039 * @fklass: The MonoClass to look up.
1040 * @field: The MonoClassField describing the field.
1042 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1043 * SPECIAL_STATIC_NONE otherwise.
1046 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1048 MONO_REQ_GC_NEUTRAL_MODE;
1050 MonoCustomAttrInfo *ainfo;
1052 ainfo = mono_custom_attrs_from_field (fklass, field);
1055 for (i = 0; i < ainfo->num_attrs; ++i) {
1056 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1057 if (klass->image == mono_defaults.corlib) {
1058 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1059 mono_custom_attrs_free (ainfo);
1060 return SPECIAL_STATIC_THREAD;
1062 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1063 mono_custom_attrs_free (ainfo);
1064 return SPECIAL_STATIC_CONTEXT;
1068 mono_custom_attrs_free (ainfo);
1069 return SPECIAL_STATIC_NONE;
1072 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1073 #define mix(a,b,c) { \
1074 a -= c; a ^= rot(c, 4); c += b; \
1075 b -= a; b ^= rot(a, 6); a += c; \
1076 c -= b; c ^= rot(b, 8); b += a; \
1077 a -= c; a ^= rot(c,16); c += b; \
1078 b -= a; b ^= rot(a,19); a += c; \
1079 c -= b; c ^= rot(b, 4); b += a; \
1081 #define final(a,b,c) { \
1082 c ^= b; c -= rot(b,14); \
1083 a ^= c; a -= rot(c,11); \
1084 b ^= a; b -= rot(a,25); \
1085 c ^= b; c -= rot(b,16); \
1086 a ^= c; a -= rot(c,4); \
1087 b ^= a; b -= rot(a,14); \
1088 c ^= b; c -= rot(b,24); \
1092 * mono_method_get_imt_slot:
1094 * The IMT slot is embedded into AOTed code, so this must return the same value
1095 * for the same method across all executions. This means:
1096 * - pointers shouldn't be used as hash values.
1097 * - mono_metadata_str_hash () should be used for hashing strings.
1100 mono_method_get_imt_slot (MonoMethod *method)
1102 MONO_REQ_GC_NEUTRAL_MODE;
1104 MonoMethodSignature *sig;
1106 guint32 *hashes_start, *hashes;
1110 /* This can be used to stress tests the collision code */
1114 * We do this to simplify generic sharing. It will hurt
1115 * performance in cases where a class implements two different
1116 * instantiations of the same generic interface.
1117 * The code in build_imt_slots () depends on this.
1119 if (method->is_inflated)
1120 method = ((MonoMethodInflated*)method)->declaring;
1122 sig = mono_method_signature (method);
1123 hashes_count = sig->param_count + 4;
1124 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1125 hashes = hashes_start;
1127 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1128 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1129 method->klass->name_space, method->klass->name, method->name);
1132 /* Initialize hashes */
1133 hashes [0] = mono_metadata_str_hash (method->klass->name);
1134 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1135 hashes [2] = mono_metadata_str_hash (method->name);
1136 hashes [3] = mono_metadata_type_hash (sig->ret);
1137 for (i = 0; i < sig->param_count; i++) {
1138 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1141 /* Setup internal state */
1142 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1144 /* Handle most of the hashes */
1145 while (hashes_count > 3) {
1154 /* Handle the last 3 hashes (all the case statements fall through) */
1155 switch (hashes_count) {
1156 case 3 : c += hashes [2];
1157 case 2 : b += hashes [1];
1158 case 1 : a += hashes [0];
1160 case 0: /* nothing left to add */
1164 free (hashes_start);
1165 /* Report the result */
1166 return c % MONO_IMT_SIZE;
1175 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1176 MONO_REQ_GC_NEUTRAL_MODE;
1178 guint32 imt_slot = mono_method_get_imt_slot (method);
1179 MonoImtBuilderEntry *entry;
1181 if (slot_num >= 0 && imt_slot != slot_num) {
1182 /* we build just a single imt slot and this is not it */
1186 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1187 entry->key = method;
1188 entry->value.vtable_slot = vtable_slot;
1189 entry->next = imt_builder [imt_slot];
1190 if (imt_builder [imt_slot] != NULL) {
1191 entry->children = imt_builder [imt_slot]->children + 1;
1192 if (entry->children == 1) {
1193 mono_stats.imt_slots_with_collisions++;
1194 *imt_collisions_bitmap |= (1 << imt_slot);
1197 entry->children = 0;
1198 mono_stats.imt_used_slots++;
1200 imt_builder [imt_slot] = entry;
1203 char *method_name = mono_method_full_name (method, TRUE);
1204 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1205 method, method_name, imt_slot, vtable_slot, entry->children);
1206 g_free (method_name);
1213 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1215 MonoMethod *method = e->key;
1216 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1220 method->klass->name_space,
1221 method->klass->name,
1224 printf (" * %s: NULL\n", message);
1230 compare_imt_builder_entries (const void *p1, const void *p2) {
1231 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1232 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1234 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1238 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1240 MONO_REQ_GC_NEUTRAL_MODE;
1242 int count = end - start;
1243 int chunk_start = out_array->len;
1246 for (i = start; i < end; ++i) {
1247 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1248 item->key = sorted_array [i]->key;
1249 item->value = sorted_array [i]->value;
1250 item->has_target_code = sorted_array [i]->has_target_code;
1251 item->is_equals = TRUE;
1253 item->check_target_idx = out_array->len + 1;
1255 item->check_target_idx = 0;
1256 g_ptr_array_add (out_array, item);
1259 int middle = start + count / 2;
1260 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1262 item->key = sorted_array [middle]->key;
1263 item->is_equals = FALSE;
1264 g_ptr_array_add (out_array, item);
1265 imt_emit_ir (sorted_array, start, middle, out_array);
1266 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1272 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1273 MONO_REQ_GC_NEUTRAL_MODE;
1275 int number_of_entries = entries->children + 1;
1276 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1277 GPtrArray *result = g_ptr_array_new ();
1278 MonoImtBuilderEntry *current_entry;
1281 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1282 sorted_array [i] = current_entry;
1284 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1286 /*for (i = 0; i < number_of_entries; i++) {
1287 print_imt_entry (" sorted array:", sorted_array [i], i);
1290 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1292 free (sorted_array);
1297 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1299 MONO_REQ_GC_NEUTRAL_MODE;
1301 if (imt_builder_entry != NULL) {
1302 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1303 /* No collision, return the vtable slot contents */
1304 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1306 /* Collision, build the thunk */
1307 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1310 result = imt_thunk_builder (vtable, domain,
1311 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1312 for (i = 0; i < imt_ir->len; ++i)
1313 g_free (g_ptr_array_index (imt_ir, i));
1314 g_ptr_array_free (imt_ir, TRUE);
1326 static MonoImtBuilderEntry*
1327 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1330 * LOCKING: requires the loader and domain locks.
1334 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1336 MONO_REQ_GC_NEUTRAL_MODE;
1340 guint32 imt_collisions_bitmap = 0;
1341 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1342 int method_count = 0;
1343 gboolean record_method_count_for_max_collisions = FALSE;
1344 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1347 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1349 for (i = 0; i < klass->interface_offsets_count; ++i) {
1350 MonoClass *iface = klass->interfaces_packed [i];
1351 int interface_offset = klass->interface_offsets_packed [i];
1352 int method_slot_in_interface, vt_slot;
1354 if (mono_class_has_variant_generic_params (iface))
1355 has_variant_iface = TRUE;
1357 mono_class_setup_methods (iface);
1358 vt_slot = interface_offset;
1359 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1362 if (slot_num >= 0 && iface->is_inflated) {
1364 * The imt slot of the method is the same as for its declaring method,
1365 * see the comment in mono_method_get_imt_slot (), so we can
1366 * avoid inflating methods which will be discarded by
1367 * add_imt_builder_entry anyway.
1369 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1370 if (mono_method_get_imt_slot (method) != slot_num) {
1375 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1376 if (method->is_generic) {
1377 has_generic_virtual = TRUE;
1382 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1383 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1388 if (extra_interfaces) {
1389 int interface_offset = klass->vtable_size;
1391 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1392 MonoClass* iface = (MonoClass *)list_item->data;
1393 int method_slot_in_interface;
1394 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1395 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1397 if (method->is_generic)
1398 has_generic_virtual = TRUE;
1399 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1401 interface_offset += iface->method.count;
1404 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1405 /* overwrite the imt slot only if we're building all the entries or if
1406 * we're building this specific one
1408 if (slot_num < 0 || i == slot_num) {
1409 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1412 if (imt_builder [i]) {
1413 MonoImtBuilderEntry *entry;
1415 /* Link entries with imt_builder [i] */
1416 for (entry = entries; entry->next; entry = entry->next) {
1418 MonoMethod *method = (MonoMethod*)entry->key;
1419 char *method_name = mono_method_full_name (method, TRUE);
1420 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1421 g_free (method_name);
1424 entry->next = imt_builder [i];
1425 entries->children += imt_builder [i]->children + 1;
1427 imt_builder [i] = entries;
1430 if (has_generic_virtual || has_variant_iface) {
1432 * There might be collisions later when the the thunk is expanded.
1434 imt_collisions_bitmap |= (1 << i);
1437 * The IMT thunk might be called with an instance of one of the
1438 * generic virtual methods, so has to fallback to the IMT trampoline.
1440 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1442 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1445 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1449 if (imt_builder [i] != NULL) {
1450 int methods_in_slot = imt_builder [i]->children + 1;
1451 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1452 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1453 record_method_count_for_max_collisions = TRUE;
1455 method_count += methods_in_slot;
1459 mono_stats.imt_number_of_methods += method_count;
1460 if (record_method_count_for_max_collisions) {
1461 mono_stats.imt_method_count_when_max_collisions = method_count;
1464 for (i = 0; i < MONO_IMT_SIZE; i++) {
1465 MonoImtBuilderEntry* entry = imt_builder [i];
1466 while (entry != NULL) {
1467 MonoImtBuilderEntry* next = entry->next;
1473 /* we OR the bitmap since we may build just a single imt slot at a time */
1474 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1478 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1479 MONO_REQ_GC_NEUTRAL_MODE;
1481 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1485 * mono_vtable_build_imt_slot:
1486 * @vtable: virtual object table struct
1487 * @imt_slot: slot in the IMT table
1489 * Fill the given @imt_slot in the IMT table of @vtable with
1490 * a trampoline or a thunk for the case of collisions.
1491 * This is part of the internal mono API.
1493 * LOCKING: Take the domain lock.
1496 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1498 MONO_REQ_GC_NEUTRAL_MODE;
1500 gpointer *imt = (gpointer*)vtable;
1501 imt -= MONO_IMT_SIZE;
1502 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1504 /* no support for extra interfaces: the proxy objects will need
1505 * to build the complete IMT
1506 * Update and heck needs to ahppen inside the proper domain lock, as all
1507 * the changes made to a MonoVTable.
1509 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1510 mono_domain_lock (vtable->domain);
1511 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1512 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1513 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1514 mono_domain_unlock (vtable->domain);
1515 mono_loader_unlock ();
1520 * The first two free list entries both belong to the wait list: The
1521 * first entry is the pointer to the head of the list and the second
1522 * entry points to the last element. That way appending and removing
1523 * the first element are both O(1) operations.
1525 #ifdef MONO_SMALL_CONFIG
1526 #define NUM_FREE_LISTS 6
1528 #define NUM_FREE_LISTS 12
1530 #define FIRST_FREE_LIST_SIZE 64
1531 #define MAX_WAIT_LENGTH 50
1532 #define THUNK_THRESHOLD 10
1535 * LOCKING: The domain lock must be held.
1538 init_thunk_free_lists (MonoDomain *domain)
1540 MONO_REQ_GC_NEUTRAL_MODE;
1542 if (domain->thunk_free_lists)
1544 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1548 list_index_for_size (int item_size)
1551 int size = FIRST_FREE_LIST_SIZE;
1553 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1562 * mono_method_alloc_generic_virtual_thunk:
1564 * @size: size in bytes
1566 * Allocs size bytes to be used for the code of a generic virtual
1567 * thunk. It's either allocated from the domain's code manager or
1568 * reused from a previously invalidated piece.
1570 * LOCKING: The domain lock must be held.
1573 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1575 MONO_REQ_GC_NEUTRAL_MODE;
1577 static gboolean inited = FALSE;
1578 static int generic_virtual_thunks_size = 0;
1582 MonoThunkFreeList **l;
1584 init_thunk_free_lists (domain);
1586 size += sizeof (guint32);
1587 if (size < sizeof (MonoThunkFreeList))
1588 size = sizeof (MonoThunkFreeList);
1590 i = list_index_for_size (size);
1591 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1592 if ((*l)->size >= size) {
1593 MonoThunkFreeList *item = *l;
1595 return ((guint32*)item) + 1;
1599 /* no suitable item found - search lists of larger sizes */
1600 while (++i < NUM_FREE_LISTS) {
1601 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1604 g_assert (item->size > size);
1605 domain->thunk_free_lists [i] = item->next;
1606 return ((guint32*)item) + 1;
1609 /* still nothing found - allocate it */
1611 mono_counters_register ("Generic virtual thunk bytes",
1612 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1615 generic_virtual_thunks_size += size;
1617 p = (guint32 *)mono_domain_code_reserve (domain, size);
1620 mono_domain_lock (domain);
1621 if (!domain->generic_virtual_thunks)
1622 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1623 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1624 mono_domain_unlock (domain);
1630 * LOCKING: The domain lock must be held.
1633 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1635 MONO_REQ_GC_NEUTRAL_MODE;
1637 guint32 *p = (guint32 *)code;
1638 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1639 gboolean found = FALSE;
1641 mono_domain_lock (domain);
1642 if (!domain->generic_virtual_thunks)
1643 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1644 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1646 mono_domain_unlock (domain);
1649 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1651 init_thunk_free_lists (domain);
1653 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1654 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1655 int length = item->length;
1658 /* unlink the first item from the wait list */
1659 domain->thunk_free_lists [0] = item->next;
1660 domain->thunk_free_lists [0]->length = length - 1;
1662 i = list_index_for_size (item->size);
1664 /* put it in the free list */
1665 item->next = domain->thunk_free_lists [i];
1666 domain->thunk_free_lists [i] = item;
1670 if (domain->thunk_free_lists [1]) {
1671 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1672 domain->thunk_free_lists [0]->length++;
1674 g_assert (!domain->thunk_free_lists [0]);
1676 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1677 domain->thunk_free_lists [0]->length = 1;
1681 typedef struct _GenericVirtualCase {
1685 struct _GenericVirtualCase *next;
1686 } GenericVirtualCase;
1689 * get_generic_virtual_entries:
1691 * Return IMT entries for the generic virtual method instances and
1692 * variant interface methods for vtable slot
1695 static MonoImtBuilderEntry*
1696 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1698 MONO_REQ_GC_NEUTRAL_MODE;
1700 GenericVirtualCase *list;
1701 MonoImtBuilderEntry *entries;
1703 mono_domain_lock (domain);
1704 if (!domain->generic_virtual_cases)
1705 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1707 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 for (; list; list = list->next) {
1711 MonoImtBuilderEntry *entry;
1713 if (list->count < THUNK_THRESHOLD)
1716 entry = g_new0 (MonoImtBuilderEntry, 1);
1717 entry->key = list->method;
1718 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1719 entry->has_target_code = 1;
1721 entry->children = entries->children + 1;
1722 entry->next = entries;
1726 mono_domain_unlock (domain);
1728 /* FIXME: Leaking memory ? */
1733 * mono_method_add_generic_virtual_invocation:
1735 * @vtable_slot: pointer to the vtable slot
1736 * @method: the inflated generic virtual method
1737 * @code: the method's code
1739 * Registers a call via unmanaged code to a generic virtual method
1740 * instantiation or variant interface method. If the number of calls reaches a threshold
1741 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1742 * virtual method thunk.
1745 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1746 gpointer *vtable_slot,
1747 MonoMethod *method, gpointer code)
1749 MONO_REQ_GC_NEUTRAL_MODE;
1751 static gboolean inited = FALSE;
1752 static int num_added = 0;
1754 GenericVirtualCase *gvc, *list;
1755 MonoImtBuilderEntry *entries;
1759 mono_domain_lock (domain);
1760 if (!domain->generic_virtual_cases)
1761 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1763 /* Check whether the case was already added */
1764 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1767 if (gvc->method == method)
1772 /* If not found, make a new one */
1774 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1775 gvc->method = method;
1778 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1780 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1783 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1789 if (++gvc->count == THUNK_THRESHOLD) {
1790 gpointer *old_thunk = (void **)*vtable_slot;
1791 gpointer vtable_trampoline = NULL;
1792 gpointer imt_trampoline = NULL;
1794 if ((gpointer)vtable_slot < (gpointer)vtable) {
1795 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1796 int imt_slot = MONO_IMT_SIZE + displacement;
1798 /* Force the rebuild of the thunk at the next call */
1799 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1800 *vtable_slot = imt_trampoline;
1802 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1804 entries = get_generic_virtual_entries (domain, vtable_slot);
1806 sorted = imt_sort_slot_entries (entries);
1808 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1812 MonoImtBuilderEntry *next = entries->next;
1817 for (i = 0; i < sorted->len; ++i)
1818 g_free (g_ptr_array_index (sorted, i));
1819 g_ptr_array_free (sorted, TRUE);
1822 #ifndef __native_client__
1823 /* We don't re-use any thunks as there is a lot of overhead */
1824 /* to deleting and re-using code in Native Client. */
1825 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1826 invalidate_generic_virtual_thunk (domain, old_thunk);
1830 mono_domain_unlock (domain);
1833 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1836 * mono_class_vtable:
1837 * @domain: the application domain
1838 * @class: the class to initialize
1840 * VTables are domain specific because we create domain specific code, and
1841 * they contain the domain specific static class data.
1842 * On failure, NULL is returned, and class->exception_type is set.
1845 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1847 return mono_class_vtable_full (domain, klass, FALSE);
1851 * mono_class_vtable_full:
1852 * @domain: the application domain
1853 * @class: the class to initialize
1854 * @raise_on_error if an exception should be raised on failure or not
1856 * VTables are domain specific because we create domain specific code, and
1857 * they contain the domain specific static class data.
1860 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1862 MONO_REQ_GC_UNSAFE_MODE;
1864 MonoClassRuntimeInfo *runtime_info;
1868 if (klass->exception_type) {
1870 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1874 /* this check can be inlined in jitted code, too */
1875 runtime_info = klass->runtime_info;
1876 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1877 return runtime_info->domain_vtables [domain->domain_id];
1878 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1882 * mono_class_try_get_vtable:
1883 * @domain: the application domain
1884 * @class: the class to initialize
1886 * This function tries to get the associated vtable from @class if
1887 * it was already created.
1890 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1892 MONO_REQ_GC_NEUTRAL_MODE;
1894 MonoClassRuntimeInfo *runtime_info;
1898 runtime_info = klass->runtime_info;
1899 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1900 return runtime_info->domain_vtables [domain->domain_id];
1905 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1907 MONO_REQ_GC_NEUTRAL_MODE;
1909 size_t alloc_offset;
1912 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1913 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1914 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1916 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1917 g_assert ((imt_table_bytes & 7) == 4);
1924 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1928 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1930 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_checked (domain, &klass->byval_arg, &error);
2180 mono_error_raise_exception (&error); /* FIXME don't raise here */
2182 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2183 /* This is unregistered in
2184 unregister_vtable_reflection_type() in
2186 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2189 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2191 /* class_vtable_array keeps an array of created vtables
2193 g_ptr_array_add (domain->class_vtable_array, vt);
2194 /* klass->runtime_info is protected by the loader lock, both when
2195 * it it enlarged and when it is stored info.
2199 * Store the vtable in klass->runtime_info.
2200 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2202 mono_memory_barrier ();
2204 old_info = klass->runtime_info;
2205 if (old_info && old_info->max_domain >= domain->domain_id) {
2206 /* someone already created a large enough runtime info */
2207 old_info->domain_vtables [domain->domain_id] = vt;
2209 int new_size = domain->domain_id;
2211 new_size = MAX (new_size, old_info->max_domain);
2213 /* make the new size a power of two */
2215 while (new_size > i)
2218 /* this is a bounded memory retention issue: may want to
2219 * handle it differently when we'll have a rcu-like system.
2221 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2222 runtime_info->max_domain = new_size - 1;
2223 /* copy the stuff from the older info */
2225 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2227 runtime_info->domain_vtables [domain->domain_id] = vt;
2229 mono_memory_barrier ();
2230 klass->runtime_info = runtime_info;
2233 if (klass == mono_defaults.monotype_class) {
2234 /*FIXME check for OOM*/
2235 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2236 mono_error_raise_exception (&error); /* FIXME don't raise here */
2238 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2239 /* This is unregistered in
2240 unregister_vtable_reflection_type() in
2242 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2245 mono_domain_unlock (domain);
2246 mono_loader_unlock ();
2248 /* make sure the parent is initialized */
2249 /*FIXME shouldn't this fail the current type?*/
2251 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2256 #ifndef DISABLE_REMOTING
2258 * mono_class_proxy_vtable:
2259 * @domain: the application domain
2260 * @remove_class: the remote class
2262 * Creates a vtable for transparent proxies. It is basically
2263 * a copy of the real vtable of the class wrapped in @remote_class,
2264 * but all function pointers invoke the remoting functions, and
2265 * vtable->klass points to the transparent proxy class, and not to @class.
2268 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2270 MONO_REQ_GC_UNSAFE_MODE;
2273 MonoVTable *vt, *pvt;
2274 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2276 GSList *extra_interfaces = NULL;
2277 MonoClass *klass = remote_class->proxy_class;
2278 gpointer *interface_offsets;
2281 size_t imt_table_bytes;
2283 #ifdef COMPRESSED_INTERFACE_BITMAP
2287 vt = mono_class_vtable (domain, klass);
2288 g_assert (vt); /*FIXME property handle failure*/
2289 max_interface_id = vt->max_interface_id;
2291 /* Calculate vtable space for extra interfaces */
2292 for (j = 0; j < remote_class->interface_count; j++) {
2293 MonoClass* iclass = remote_class->interfaces[j];
2297 /*FIXME test for interfaces with variant generic arguments*/
2298 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2299 continue; /* interface implemented by the class */
2300 if (g_slist_find (extra_interfaces, iclass))
2303 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2305 method_count = mono_class_num_methods (iclass);
2307 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2308 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2310 for (i = 0; i < ifaces->len; ++i) {
2311 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2312 /*FIXME test for interfaces with variant generic arguments*/
2313 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2314 continue; /* interface implemented by the class */
2315 if (g_slist_find (extra_interfaces, ic))
2317 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2318 method_count += mono_class_num_methods (ic);
2320 g_ptr_array_free (ifaces, TRUE);
2323 extra_interface_vtsize += method_count * sizeof (gpointer);
2324 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2327 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2328 mono_stats.imt_number_of_tables++;
2329 mono_stats.imt_tables_size += imt_table_bytes;
2331 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2333 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2335 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2336 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2337 g_assert (!((gsize)pvt & 7));
2339 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2341 pvt->klass = mono_defaults.transparent_proxy_class;
2342 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2343 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2345 /* initialize vtable */
2346 mono_class_setup_vtable (klass);
2347 for (i = 0; i < klass->vtable_size; ++i) {
2350 if ((cm = klass->vtable [i]))
2351 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2353 pvt->vtable [i] = NULL;
2356 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2357 /* create trampolines for abstract methods */
2358 for (k = klass; k; k = k->parent) {
2360 gpointer iter = NULL;
2361 while ((m = mono_class_get_methods (k, &iter)))
2362 if (!pvt->vtable [m->slot])
2363 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2367 pvt->max_interface_id = max_interface_id;
2368 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2369 #ifdef COMPRESSED_INTERFACE_BITMAP
2370 bitmap = (uint8_t *)g_malloc0 (bsize);
2372 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2375 for (i = 0; i < klass->interface_offsets_count; ++i) {
2376 int interface_id = klass->interfaces_packed [i]->interface_id;
2377 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2380 if (extra_interfaces) {
2381 int slot = klass->vtable_size;
2387 /* Create trampolines for the methods of the interfaces */
2388 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2389 interf = (MonoClass *)list_item->data;
2391 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2395 while ((cm = mono_class_get_methods (interf, &iter)))
2396 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2398 slot += mono_class_num_methods (interf);
2402 /* Now that the vtable is full, we can actually fill up the IMT */
2403 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2404 if (extra_interfaces) {
2405 g_slist_free (extra_interfaces);
2408 #ifdef COMPRESSED_INTERFACE_BITMAP
2409 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2410 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2411 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2414 pvt->interface_bitmap = bitmap;
2419 #endif /* DISABLE_REMOTING */
2422 * mono_class_field_is_special_static:
2424 * Returns whether @field is a thread/context static field.
2427 mono_class_field_is_special_static (MonoClassField *field)
2429 MONO_REQ_GC_NEUTRAL_MODE
2431 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2433 if (mono_field_is_deleted (field))
2435 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2436 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2443 * mono_class_field_get_special_static_type:
2444 * @field: The MonoClassField describing the field.
2446 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2447 * SPECIAL_STATIC_NONE otherwise.
2450 mono_class_field_get_special_static_type (MonoClassField *field)
2452 MONO_REQ_GC_NEUTRAL_MODE
2454 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2455 return SPECIAL_STATIC_NONE;
2456 if (mono_field_is_deleted (field))
2457 return SPECIAL_STATIC_NONE;
2458 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2459 return field_is_special_static (field->parent, field);
2460 return SPECIAL_STATIC_NONE;
2464 * mono_class_has_special_static_fields:
2466 * Returns whenever @klass has any thread/context static fields.
2469 mono_class_has_special_static_fields (MonoClass *klass)
2471 MONO_REQ_GC_NEUTRAL_MODE
2473 MonoClassField *field;
2477 while ((field = mono_class_get_fields (klass, &iter))) {
2478 g_assert (field->parent == klass);
2479 if (mono_class_field_is_special_static (field))
2486 #ifndef DISABLE_REMOTING
2488 * create_remote_class_key:
2489 * Creates an array of pointers that can be used as a hash key for a remote class.
2490 * The first element of the array is the number of pointers.
2493 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2495 MONO_REQ_GC_NEUTRAL_MODE;
2500 if (remote_class == NULL) {
2501 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2502 key = (void **)g_malloc (sizeof(gpointer) * 3);
2503 key [0] = GINT_TO_POINTER (2);
2504 key [1] = mono_defaults.marshalbyrefobject_class;
2505 key [2] = extra_class;
2507 key = (void **)g_malloc (sizeof(gpointer) * 2);
2508 key [0] = GINT_TO_POINTER (1);
2509 key [1] = extra_class;
2512 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2513 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2514 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2515 key [1] = remote_class->proxy_class;
2517 // Keep the list of interfaces sorted
2518 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2519 if (extra_class && remote_class->interfaces [i] > extra_class) {
2520 key [j++] = extra_class;
2523 key [j] = remote_class->interfaces [i];
2526 key [j] = extra_class;
2528 // Replace the old class. The interface list is the same
2529 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2530 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2531 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2532 for (i = 0; i < remote_class->interface_count; i++)
2533 key [2 + i] = remote_class->interfaces [i];
2541 * copy_remote_class_key:
2543 * Make a copy of KEY in the domain and return the copy.
2546 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2548 MONO_REQ_GC_NEUTRAL_MODE
2550 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2551 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2553 memcpy (mp_key, key, key_size);
2559 * mono_remote_class:
2560 * @domain: the application domain
2561 * @class_name: name of the remote class
2563 * Creates and initializes a MonoRemoteClass object for a remote type.
2565 * Can raise an exception on failure.
2568 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2570 MONO_REQ_GC_UNSAFE_MODE;
2573 MonoRemoteClass *rc;
2574 gpointer* key, *mp_key;
2577 key = create_remote_class_key (NULL, proxy_class);
2579 mono_domain_lock (domain);
2580 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2584 mono_domain_unlock (domain);
2588 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2589 if (!mono_error_ok (&error)) {
2591 mono_domain_unlock (domain);
2592 mono_error_raise_exception (&error);
2595 mp_key = copy_remote_class_key (domain, key);
2599 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2600 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2601 rc->interface_count = 1;
2602 rc->interfaces [0] = proxy_class;
2603 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2605 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2606 rc->interface_count = 0;
2607 rc->proxy_class = proxy_class;
2610 rc->default_vtable = NULL;
2611 rc->xdomain_vtable = NULL;
2612 rc->proxy_class_name = name;
2613 #ifndef DISABLE_PERFCOUNTERS
2614 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2617 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2619 mono_domain_unlock (domain);
2624 * clone_remote_class:
2625 * Creates a copy of the remote_class, adding the provided class or interface
2627 static MonoRemoteClass*
2628 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2630 MONO_REQ_GC_NEUTRAL_MODE;
2632 MonoRemoteClass *rc;
2633 gpointer* key, *mp_key;
2635 key = create_remote_class_key (remote_class, extra_class);
2636 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2642 mp_key = copy_remote_class_key (domain, key);
2646 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2648 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2649 rc->proxy_class = remote_class->proxy_class;
2650 rc->interface_count = remote_class->interface_count + 1;
2652 // Keep the list of interfaces sorted, since the hash key of
2653 // the remote class depends on this
2654 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2655 if (remote_class->interfaces [i] > extra_class && i == j)
2656 rc->interfaces [j++] = extra_class;
2657 rc->interfaces [j] = remote_class->interfaces [i];
2660 rc->interfaces [j] = extra_class;
2662 // Replace the old class. The interface array is the same
2663 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2664 rc->proxy_class = extra_class;
2665 rc->interface_count = remote_class->interface_count;
2666 if (rc->interface_count > 0)
2667 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2670 rc->default_vtable = NULL;
2671 rc->xdomain_vtable = NULL;
2672 rc->proxy_class_name = remote_class->proxy_class_name;
2674 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2680 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2682 MONO_REQ_GC_UNSAFE_MODE;
2684 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2685 mono_domain_lock (domain);
2686 if (rp->target_domain_id != -1) {
2687 if (remote_class->xdomain_vtable == NULL)
2688 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2689 mono_domain_unlock (domain);
2690 mono_loader_unlock ();
2691 return remote_class->xdomain_vtable;
2693 if (remote_class->default_vtable == NULL) {
2696 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2697 klass = mono_class_from_mono_type (type);
2699 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)))
2700 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2703 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2706 mono_domain_unlock (domain);
2707 mono_loader_unlock ();
2708 return remote_class->default_vtable;
2712 * mono_upgrade_remote_class:
2713 * @domain: the application domain
2714 * @tproxy: the proxy whose remote class has to be upgraded.
2715 * @klass: class to which the remote class can be casted.
2717 * Updates the vtable of the remote class by adding the necessary method slots
2718 * and interface offsets so it can be safely casted to klass. klass can be a
2719 * class or an interface.
2722 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2724 MONO_REQ_GC_UNSAFE_MODE;
2726 MonoTransparentProxy *tproxy;
2727 MonoRemoteClass *remote_class;
2728 gboolean redo_vtable;
2730 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2731 mono_domain_lock (domain);
2733 tproxy = (MonoTransparentProxy*) proxy_object;
2734 remote_class = tproxy->remote_class;
2736 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2739 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2740 if (remote_class->interfaces [i] == klass)
2741 redo_vtable = FALSE;
2744 redo_vtable = (remote_class->proxy_class != klass);
2748 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2749 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2752 mono_domain_unlock (domain);
2753 mono_loader_unlock ();
2755 #endif /* DISABLE_REMOTING */
2759 * mono_object_get_virtual_method:
2760 * @obj: object to operate on.
2763 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2764 * the instance of a callvirt of method.
2767 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2769 MONO_REQ_GC_UNSAFE_MODE;
2772 MonoMethod **vtable;
2773 gboolean is_proxy = FALSE;
2774 MonoMethod *res = NULL;
2776 klass = mono_object_class (obj);
2777 #ifndef DISABLE_REMOTING
2778 if (klass == mono_defaults.transparent_proxy_class) {
2779 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2784 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2787 mono_class_setup_vtable (klass);
2788 vtable = klass->vtable;
2790 if (method->slot == -1) {
2791 /* method->slot might not be set for instances of generic methods */
2792 if (method->is_inflated) {
2793 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2794 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2797 g_assert_not_reached ();
2801 /* check method->slot is a valid index: perform isinstance? */
2802 if (method->slot != -1) {
2803 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2805 gboolean variance_used = FALSE;
2806 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2807 g_assert (iface_offset > 0);
2808 res = vtable [iface_offset + method->slot];
2811 res = vtable [method->slot];
2815 #ifndef DISABLE_REMOTING
2817 /* It may be an interface, abstract class method or generic method */
2818 if (!res || mono_method_signature (res)->generic_param_count)
2821 /* generic methods demand invoke_with_check */
2822 if (mono_method_signature (res)->generic_param_count)
2823 res = mono_marshal_get_remoting_invoke_with_check (res);
2826 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2827 res = mono_cominterop_get_invoke (res);
2830 res = mono_marshal_get_remoting_invoke (res);
2835 if (method->is_inflated) {
2837 /* Have to inflate the result */
2838 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2839 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2849 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2851 g_error ("runtime invoke called on uninitialized runtime");
2855 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2858 * mono_runtime_invoke:
2859 * @method: method to invoke
2860 * @obJ: object instance
2861 * @params: arguments to the method
2862 * @exc: exception information.
2864 * Invokes the method represented by @method on the object @obj.
2866 * obj is the 'this' pointer, it should be NULL for static
2867 * methods, a MonoObject* for object instances and a pointer to
2868 * the value type for value types.
2870 * The params array contains the arguments to the method with the
2871 * same convention: MonoObject* pointers for object instances and
2872 * pointers to the value type otherwise.
2874 * From unmanaged code you'll usually use the
2875 * mono_runtime_invoke() variant.
2877 * Note that this function doesn't handle virtual methods for
2878 * you, it will exec the exact method you pass: we still need to
2879 * expose a function to lookup the derived class implementation
2880 * of a virtual method (there are examples of this in the code,
2883 * You can pass NULL as the exc argument if you don't want to
2884 * catch exceptions, otherwise, *exc will be set to the exception
2885 * thrown, if any. if an exception is thrown, you can't use the
2886 * MonoObject* result from the function.
2888 * If the method returns a value type, it is boxed in an object
2892 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2894 MONO_REQ_GC_UNSAFE_MODE;
2898 if (mono_runtime_get_no_exec ())
2899 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2901 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2902 mono_profiler_method_start_invoke (method);
2904 result = default_mono_runtime_invoke (method, obj, params, exc);
2906 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2907 mono_profiler_method_end_invoke (method);
2913 * mono_method_get_unmanaged_thunk:
2914 * @method: method to generate a thunk for.
2916 * Returns an unmanaged->managed thunk that can be used to call
2917 * a managed method directly from C.
2919 * The thunk's C signature closely matches the managed signature:
2921 * C#: public bool Equals (object obj);
2922 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2923 * MonoObject*, MonoException**);
2925 * The 1st ("this") parameter must not be used with static methods:
2927 * C#: public static bool ReferenceEquals (object a, object b);
2928 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2931 * The last argument must be a non-null pointer of a MonoException* pointer.
2932 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2933 * exception has been thrown in managed code. Otherwise it will point
2934 * to the MonoException* caught by the thunk. In this case, the result of
2935 * the thunk is undefined:
2937 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2938 * MonoException *ex = NULL;
2939 * Equals func = mono_method_get_unmanaged_thunk (method);
2940 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2942 * // handle exception
2945 * The calling convention of the thunk matches the platform's default
2946 * convention. This means that under Windows, C declarations must
2947 * contain the __stdcall attribute:
2949 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2950 * MonoObject*, MonoException**);
2954 * Value type arguments and return values are treated as they were objects:
2956 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2957 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2959 * Arguments must be properly boxed upon trunk's invocation, while return
2960 * values must be unboxed.
2963 mono_method_get_unmanaged_thunk (MonoMethod *method)
2965 MONO_REQ_GC_NEUTRAL_MODE;
2966 MONO_REQ_API_ENTRYPOINT;
2970 MONO_PREPARE_RESET_BLOCKING;
2971 method = mono_marshal_get_thunk_invoke_wrapper (method);
2972 res = mono_compile_method (method);
2973 MONO_FINISH_RESET_BLOCKING;
2979 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2981 MONO_REQ_GC_UNSAFE_MODE;
2985 /* object fields cannot be byref, so we don't need a
2987 gpointer *p = (gpointer*)dest;
2994 case MONO_TYPE_BOOLEAN:
2996 case MONO_TYPE_U1: {
2997 guint8 *p = (guint8*)dest;
2998 *p = value ? *(guint8*)value : 0;
3003 case MONO_TYPE_CHAR: {
3004 guint16 *p = (guint16*)dest;
3005 *p = value ? *(guint16*)value : 0;
3008 #if SIZEOF_VOID_P == 4
3013 case MONO_TYPE_U4: {
3014 gint32 *p = (gint32*)dest;
3015 *p = value ? *(gint32*)value : 0;
3018 #if SIZEOF_VOID_P == 8
3023 case MONO_TYPE_U8: {
3024 gint64 *p = (gint64*)dest;
3025 *p = value ? *(gint64*)value : 0;
3028 case MONO_TYPE_R4: {
3029 float *p = (float*)dest;
3030 *p = value ? *(float*)value : 0;
3033 case MONO_TYPE_R8: {
3034 double *p = (double*)dest;
3035 *p = value ? *(double*)value : 0;
3038 case MONO_TYPE_STRING:
3039 case MONO_TYPE_SZARRAY:
3040 case MONO_TYPE_CLASS:
3041 case MONO_TYPE_OBJECT:
3042 case MONO_TYPE_ARRAY:
3043 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3045 case MONO_TYPE_FNPTR:
3046 case MONO_TYPE_PTR: {
3047 gpointer *p = (gpointer*)dest;
3048 *p = deref_pointer? *(gpointer*)value: value;
3051 case MONO_TYPE_VALUETYPE:
3052 /* note that 't' and 'type->type' can be different */
3053 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3054 t = mono_class_enum_basetype (type->data.klass)->type;
3057 MonoClass *klass = mono_class_from_mono_type (type);
3058 int size = mono_class_value_size (klass, NULL);
3060 mono_gc_bzero_atomic (dest, size);
3062 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3065 case MONO_TYPE_GENERICINST:
3066 t = type->data.generic_class->container_class->byval_arg.type;
3069 g_error ("got type %x", type->type);
3074 * mono_field_set_value:
3075 * @obj: Instance object
3076 * @field: MonoClassField describing the field to set
3077 * @value: The value to be set
3079 * Sets the value of the field described by @field in the object instance @obj
3080 * to the value passed in @value. This method should only be used for instance
3081 * fields. For static fields, use mono_field_static_set_value.
3083 * The value must be on the native format of the field type.
3086 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3088 MONO_REQ_GC_UNSAFE_MODE;
3092 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3094 dest = (char*)obj + field->offset;
3095 mono_copy_value (field->type, dest, value, FALSE);
3099 * mono_field_static_set_value:
3100 * @field: MonoClassField describing the field to set
3101 * @value: The value to be set
3103 * Sets the value of the static field described by @field
3104 * to the value passed in @value.
3106 * The value must be on the native format of the field type.
3109 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3111 MONO_REQ_GC_UNSAFE_MODE;
3115 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3116 /* you cant set a constant! */
3117 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3119 if (field->offset == -1) {
3120 /* Special static */
3123 mono_domain_lock (vt->domain);
3124 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3125 mono_domain_unlock (vt->domain);
3126 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3128 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3130 mono_copy_value (field->type, dest, value, FALSE);
3134 * mono_vtable_get_static_field_data:
3136 * Internal use function: return a pointer to the memory holding the static fields
3137 * for a class or NULL if there are no static fields.
3138 * This is exported only for use by the debugger.
3141 mono_vtable_get_static_field_data (MonoVTable *vt)
3143 MONO_REQ_GC_NEUTRAL_MODE
3145 if (!vt->has_static_fields)
3147 return vt->vtable [vt->klass->vtable_size];
3151 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3153 MONO_REQ_GC_UNSAFE_MODE;
3157 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3158 if (field->offset == -1) {
3159 /* Special static */
3162 mono_domain_lock (vt->domain);
3163 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3164 mono_domain_unlock (vt->domain);
3165 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3167 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3170 src = (guint8*)obj + field->offset;
3177 * mono_field_get_value:
3178 * @obj: Object instance
3179 * @field: MonoClassField describing the field to fetch information from
3180 * @value: pointer to the location where the value will be stored
3182 * Use this routine to get the value of the field @field in the object
3185 * The pointer provided by value must be of the field type, for reference
3186 * types this is a MonoObject*, for value types its the actual pointer to
3191 * mono_field_get_value (obj, int_field, &i);
3194 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3196 MONO_REQ_GC_UNSAFE_MODE;
3202 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3204 src = (char*)obj + field->offset;
3205 mono_copy_value (field->type, value, src, TRUE);
3209 * mono_field_get_value_object:
3210 * @domain: domain where the object will be created (if boxing)
3211 * @field: MonoClassField describing the field to fetch information from
3212 * @obj: The object instance for the field.
3214 * Returns: a new MonoObject with the value from the given field. If the
3215 * field represents a value type, the value is boxed.
3219 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3221 MONO_REQ_GC_UNSAFE_MODE;
3226 MonoVTable *vtable = NULL;
3228 gboolean is_static = FALSE;
3229 gboolean is_ref = FALSE;
3230 gboolean is_literal = FALSE;
3231 gboolean is_ptr = FALSE;
3232 MonoType *type = mono_field_get_type_checked (field, &error);
3234 if (!mono_error_ok (&error))
3235 mono_error_raise_exception (&error);
3237 switch (type->type) {
3238 case MONO_TYPE_STRING:
3239 case MONO_TYPE_OBJECT:
3240 case MONO_TYPE_CLASS:
3241 case MONO_TYPE_ARRAY:
3242 case MONO_TYPE_SZARRAY:
3247 case MONO_TYPE_BOOLEAN:
3250 case MONO_TYPE_CHAR:
3259 case MONO_TYPE_VALUETYPE:
3260 is_ref = type->byref;
3262 case MONO_TYPE_GENERICINST:
3263 is_ref = !mono_type_generic_inst_is_valuetype (type);
3269 g_error ("type 0x%x not handled in "
3270 "mono_field_get_value_object", type->type);
3274 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3277 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3281 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3282 if (!vtable->initialized)
3283 mono_runtime_class_init (vtable);
3291 get_default_field_value (domain, field, &o);
3292 } else if (is_static) {
3293 mono_field_static_get_value (vtable, field, &o);
3295 mono_field_get_value (obj, field, &o);
3301 static MonoMethod *m;
3307 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3308 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3314 get_default_field_value (domain, field, v);
3315 } else if (is_static) {
3316 mono_field_static_get_value (vtable, field, v);
3318 mono_field_get_value (obj, field, v);
3321 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3322 args [0] = ptr ? *ptr : NULL;
3323 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3324 mono_error_raise_exception (&error); /* FIXME don't raise here */
3326 return mono_runtime_invoke (m, NULL, args, NULL);
3329 /* boxed value type */
3330 klass = mono_class_from_mono_type (type);
3332 if (mono_class_is_nullable (klass))
3333 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3335 o = mono_object_new (domain, klass);
3336 v = ((gchar *) o) + sizeof (MonoObject);
3339 get_default_field_value (domain, field, v);
3340 } else if (is_static) {
3341 mono_field_static_get_value (vtable, field, v);
3343 mono_field_get_value (obj, field, v);
3350 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3352 MONO_REQ_GC_UNSAFE_MODE;
3355 const char *p = blob;
3356 mono_metadata_decode_blob_size (p, &p);
3359 case MONO_TYPE_BOOLEAN:
3362 *(guint8 *) value = *p;
3364 case MONO_TYPE_CHAR:
3367 *(guint16*) value = read16 (p);
3371 *(guint32*) value = read32 (p);
3375 *(guint64*) value = read64 (p);
3378 readr4 (p, (float*) value);
3381 readr8 (p, (double*) value);
3383 case MONO_TYPE_STRING:
3384 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3386 case MONO_TYPE_CLASS:
3387 *(gpointer*) value = NULL;
3391 g_warning ("type 0x%02x should not be in constant table", type);
3397 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3399 MONO_REQ_GC_NEUTRAL_MODE;
3401 MonoTypeEnum def_type;
3404 data = mono_class_get_field_default_value (field, &def_type);
3405 mono_get_constant_value_from_blob (domain, def_type, data, value);
3409 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3411 MONO_REQ_GC_UNSAFE_MODE;
3415 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3417 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3418 get_default_field_value (vt->domain, field, value);
3422 if (field->offset == -1) {
3423 /* Special static */
3424 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3425 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3427 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3429 mono_copy_value (field->type, value, src, TRUE);
3433 * mono_field_static_get_value:
3434 * @vt: vtable to the object
3435 * @field: MonoClassField describing the field to fetch information from
3436 * @value: where the value is returned
3438 * Use this routine to get the value of the static field @field value.
3440 * The pointer provided by value must be of the field type, for reference
3441 * types this is a MonoObject*, for value types its the actual pointer to
3446 * mono_field_static_get_value (vt, int_field, &i);
3449 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3451 MONO_REQ_GC_NEUTRAL_MODE;
3453 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3457 * mono_property_set_value:
3458 * @prop: MonoProperty to set
3459 * @obj: instance object on which to act
3460 * @params: parameters to pass to the propery
3461 * @exc: optional exception
3463 * Invokes the property's set method with the given arguments on the
3464 * object instance obj (or NULL for static properties).
3466 * You can pass NULL as the exc argument if you don't want to
3467 * catch exceptions, otherwise, *exc will be set to the exception
3468 * thrown, if any. if an exception is thrown, you can't use the
3469 * MonoObject* result from the function.
3472 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3474 MONO_REQ_GC_UNSAFE_MODE;
3476 default_mono_runtime_invoke (prop->set, obj, params, exc);
3480 * mono_property_get_value:
3481 * @prop: MonoProperty to fetch
3482 * @obj: instance object on which to act
3483 * @params: parameters to pass to the propery
3484 * @exc: optional exception
3486 * Invokes the property's get method with the given arguments on the
3487 * object instance obj (or NULL for static properties).
3489 * You can pass NULL as the exc argument if you don't want to
3490 * catch exceptions, otherwise, *exc will be set to the exception
3491 * thrown, if any. if an exception is thrown, you can't use the
3492 * MonoObject* result from the function.
3494 * Returns: the value from invoking the get method on the property.
3497 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3499 MONO_REQ_GC_UNSAFE_MODE;
3501 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3505 * mono_nullable_init:
3506 * @buf: The nullable structure to initialize.
3507 * @value: the value to initialize from
3508 * @klass: the type for the object
3510 * Initialize the nullable structure pointed to by @buf from @value which
3511 * should be a boxed value type. The size of @buf should be able to hold
3512 * as much data as the @klass->instance_size (which is the number of bytes
3513 * that will be copies).
3515 * Since Nullables have variable structure, we can not define a C
3516 * structure for them.
3519 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3521 MONO_REQ_GC_UNSAFE_MODE;
3523 MonoClass *param_class = klass->cast_class;
3525 mono_class_setup_fields_locking (klass);
3526 g_assert (klass->fields_inited);
3528 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3529 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3531 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3533 if (param_class->has_references)
3534 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3536 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3538 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3543 * mono_nullable_box:
3544 * @buf: The buffer representing the data to be boxed
3545 * @klass: the type to box it as.
3547 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3551 mono_nullable_box (guint8 *buf, MonoClass *klass)
3553 MONO_REQ_GC_UNSAFE_MODE;
3555 MonoClass *param_class = klass->cast_class;
3557 mono_class_setup_fields_locking (klass);
3558 g_assert (klass->fields_inited);
3560 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3561 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3563 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3564 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3565 if (param_class->has_references)
3566 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3568 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3576 * mono_get_delegate_invoke:
3577 * @klass: The delegate class
3579 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3582 mono_get_delegate_invoke (MonoClass *klass)
3584 MONO_REQ_GC_NEUTRAL_MODE;
3588 /* This is called at runtime, so avoid the slower search in metadata */
3589 mono_class_setup_methods (klass);
3590 if (klass->exception_type)
3592 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3597 * mono_get_delegate_begin_invoke:
3598 * @klass: The delegate class
3600 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3603 mono_get_delegate_begin_invoke (MonoClass *klass)
3605 MONO_REQ_GC_NEUTRAL_MODE;
3609 /* This is called at runtime, so avoid the slower search in metadata */
3610 mono_class_setup_methods (klass);
3611 if (klass->exception_type)
3613 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3618 * mono_get_delegate_end_invoke:
3619 * @klass: The delegate class
3621 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3624 mono_get_delegate_end_invoke (MonoClass *klass)
3626 MONO_REQ_GC_NEUTRAL_MODE;
3630 /* This is called at runtime, so avoid the slower search in metadata */
3631 mono_class_setup_methods (klass);
3632 if (klass->exception_type)
3634 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3639 * mono_runtime_delegate_invoke:
3640 * @delegate: pointer to a delegate object.
3641 * @params: parameters for the delegate.
3642 * @exc: Pointer to the exception result.
3644 * Invokes the delegate method @delegate with the parameters provided.
3646 * You can pass NULL as the exc argument if you don't want to
3647 * catch exceptions, otherwise, *exc will be set to the exception
3648 * thrown, if any. if an exception is thrown, you can't use the
3649 * MonoObject* result from the function.
3652 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3654 MONO_REQ_GC_UNSAFE_MODE;
3657 MonoClass *klass = delegate->vtable->klass;
3659 im = mono_get_delegate_invoke (klass);
3661 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3663 return mono_runtime_invoke (im, delegate, params, exc);
3666 static char **main_args = NULL;
3667 static int num_main_args = 0;
3670 * mono_runtime_get_main_args:
3672 * Returns: a MonoArray with the arguments passed to the main program
3675 mono_runtime_get_main_args (void)
3677 MONO_REQ_GC_UNSAFE_MODE;
3681 MonoDomain *domain = mono_domain_get ();
3683 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3685 for (i = 0; i < num_main_args; ++i)
3686 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3692 free_main_args (void)
3694 MONO_REQ_GC_NEUTRAL_MODE;
3698 for (i = 0; i < num_main_args; ++i)
3699 g_free (main_args [i]);
3706 * mono_runtime_set_main_args:
3707 * @argc: number of arguments from the command line
3708 * @argv: array of strings from the command line
3710 * Set the command line arguments from an embedding application that doesn't otherwise call
3711 * mono_runtime_run_main ().
3714 mono_runtime_set_main_args (int argc, char* argv[])
3716 MONO_REQ_GC_NEUTRAL_MODE;
3721 main_args = g_new0 (char*, argc);
3722 num_main_args = argc;
3724 for (i = 0; i < argc; ++i) {
3727 utf8_arg = mono_utf8_from_external (argv[i]);
3728 if (utf8_arg == NULL) {
3729 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3730 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3734 main_args [i] = utf8_arg;
3741 * mono_runtime_run_main:
3742 * @method: the method to start the application with (usually Main)
3743 * @argc: number of arguments from the command line
3744 * @argv: array of strings from the command line
3745 * @exc: excetption results
3747 * Execute a standard Main() method (argc/argv contains the
3748 * executable name). This method also sets the command line argument value
3749 * needed by System.Environment.
3754 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3757 MONO_REQ_GC_UNSAFE_MODE;
3760 MonoArray *args = NULL;
3761 MonoDomain *domain = mono_domain_get ();
3762 gchar *utf8_fullpath;
3763 MonoMethodSignature *sig;
3765 g_assert (method != NULL);
3767 mono_thread_set_main (mono_thread_current ());
3769 main_args = g_new0 (char*, argc);
3770 num_main_args = argc;
3772 if (!g_path_is_absolute (argv [0])) {
3773 gchar *basename = g_path_get_basename (argv [0]);
3774 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3778 utf8_fullpath = mono_utf8_from_external (fullpath);
3779 if(utf8_fullpath == NULL) {
3780 /* Printing the arg text will cause glib to
3781 * whinge about "Invalid UTF-8", but at least
3782 * its relevant, and shows the problem text
3785 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3786 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3793 utf8_fullpath = mono_utf8_from_external (argv[0]);
3794 if(utf8_fullpath == NULL) {
3795 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3796 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3801 main_args [0] = utf8_fullpath;
3803 for (i = 1; i < argc; ++i) {
3806 utf8_arg=mono_utf8_from_external (argv[i]);
3807 if(utf8_arg==NULL) {
3808 /* Ditto the comment about Invalid UTF-8 here */
3809 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3810 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3814 main_args [i] = utf8_arg;
3819 sig = mono_method_signature (method);
3821 g_print ("Unable to load Main method.\n");
3825 if (sig->param_count) {
3826 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3827 for (i = 0; i < argc; ++i) {
3828 /* The encodings should all work, given that
3829 * we've checked all these args for the
3832 gchar *str = mono_utf8_from_external (argv [i]);
3833 MonoString *arg = mono_string_new (domain, str);
3834 mono_array_setref (args, i, arg);
3838 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3841 mono_assembly_set_main (method->klass->image->assembly);
3843 return mono_runtime_exec_main (method, args, exc);
3847 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3849 static MonoMethod *serialize_method;
3854 if (!serialize_method) {
3855 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3856 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3859 if (!serialize_method) {
3864 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3868 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3876 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3878 MONO_REQ_GC_UNSAFE_MODE;
3880 static MonoMethod *deserialize_method;
3885 if (!deserialize_method) {
3886 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3887 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3889 if (!deserialize_method) {
3896 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3903 #ifndef DISABLE_REMOTING
3905 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3907 MONO_REQ_GC_UNSAFE_MODE;
3909 static MonoMethod *get_proxy_method;
3912 MonoDomain *domain = mono_domain_get ();
3913 MonoRealProxy *real_proxy;
3914 MonoReflectionType *reflection_type;
3915 MonoTransparentProxy *transparent_proxy;
3917 if (!get_proxy_method)
3918 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3920 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3922 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3923 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
3924 mono_error_raise_exception (&error); /* FIXME don't raise here */
3926 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3927 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3930 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3934 return (MonoObject*) transparent_proxy;
3936 #endif /* DISABLE_REMOTING */
3939 * mono_object_xdomain_representation
3941 * @target_domain: a domain
3942 * @exc: pointer to a MonoObject*
3944 * Creates a representation of obj in the domain target_domain. This
3945 * is either a copy of obj arrived through via serialization and
3946 * deserialization or a proxy, depending on whether the object is
3947 * serializable or marshal by ref. obj must not be in target_domain.
3949 * If the object cannot be represented in target_domain, NULL is
3950 * returned and *exc is set to an appropriate exception.
3953 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3955 MONO_REQ_GC_UNSAFE_MODE;
3957 MonoObject *deserialized = NULL;
3958 gboolean failure = FALSE;
3962 #ifndef DISABLE_REMOTING
3963 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3964 deserialized = make_transparent_proxy (obj, &failure, exc);
3969 MonoDomain *domain = mono_domain_get ();
3970 MonoObject *serialized;
3972 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3973 serialized = serialize_object (obj, &failure, exc);
3974 mono_domain_set_internal_with_options (target_domain, FALSE);
3976 deserialized = deserialize_object (serialized, &failure, exc);
3977 if (domain != target_domain)
3978 mono_domain_set_internal_with_options (domain, FALSE);
3981 return deserialized;
3984 /* Used in call_unhandled_exception_delegate */
3986 create_unhandled_exception_eventargs (MonoObject *exc)
3988 MONO_REQ_GC_UNSAFE_MODE;
3992 MonoMethod *method = NULL;
3993 MonoBoolean is_terminating = TRUE;
3996 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3999 mono_class_init (klass);
4001 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4002 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4006 args [1] = &is_terminating;
4008 obj = mono_object_new (mono_domain_get (), klass);
4009 mono_runtime_invoke (method, obj, args, NULL);
4014 /* Used in mono_unhandled_exception */
4016 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4017 MONO_REQ_GC_UNSAFE_MODE;
4019 MonoObject *e = NULL;
4021 MonoDomain *current_domain = mono_domain_get ();
4023 if (domain != current_domain)
4024 mono_domain_set_internal_with_options (domain, FALSE);
4026 g_assert (domain == mono_object_domain (domain->domain));
4028 if (mono_object_domain (exc) != domain) {
4029 MonoObject *serialization_exc;
4031 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4033 if (serialization_exc) {
4035 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4038 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4039 "System.Runtime.Serialization", "SerializationException",
4040 "Could not serialize unhandled exception.");
4044 g_assert (mono_object_domain (exc) == domain);
4046 pa [0] = domain->domain;
4047 pa [1] = create_unhandled_exception_eventargs (exc);
4048 mono_runtime_delegate_invoke (delegate, pa, &e);
4050 if (domain != current_domain)
4051 mono_domain_set_internal_with_options (current_domain, FALSE);
4055 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4056 if (!mono_error_ok (&error)) {
4057 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4058 mono_error_cleanup (&error);
4060 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4066 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4069 * mono_runtime_unhandled_exception_policy_set:
4070 * @policy: the new policy
4072 * This is a VM internal routine.
4074 * Sets the runtime policy for handling unhandled exceptions.
4077 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4078 runtime_unhandled_exception_policy = policy;
4082 * mono_runtime_unhandled_exception_policy_get:
4084 * This is a VM internal routine.
4086 * Gets the runtime policy for handling unhandled exceptions.
4088 MonoRuntimeUnhandledExceptionPolicy
4089 mono_runtime_unhandled_exception_policy_get (void) {
4090 return runtime_unhandled_exception_policy;
4094 * mono_unhandled_exception:
4095 * @exc: exception thrown
4097 * This is a VM internal routine.
4099 * We call this function when we detect an unhandled exception
4100 * in the default domain.
4102 * It invokes the * UnhandledException event in AppDomain or prints
4103 * a warning to the console
4106 mono_unhandled_exception (MonoObject *exc)
4108 MONO_REQ_GC_UNSAFE_MODE;
4110 MonoClassField *field;
4111 MonoDomain *current_domain, *root_domain;
4112 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4114 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4117 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4120 current_domain = mono_domain_get ();
4121 root_domain = mono_get_root_domain ();
4123 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4124 if (current_domain != root_domain)
4125 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4127 /* set exitcode only if we will abort the process */
4128 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4129 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4130 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4132 mono_environment_exitcode_set (1);
4135 mono_print_unhandled_exception (exc);
4137 if (root_appdomain_delegate)
4138 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4139 if (current_appdomain_delegate)
4140 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4145 * mono_runtime_exec_managed_code:
4146 * @domain: Application domain
4147 * @main_func: function to invoke from the execution thread
4148 * @main_args: parameter to the main_func
4150 * Launch a new thread to execute a function
4152 * main_func is called back from the thread with main_args as the
4153 * parameter. The callback function is expected to start Main()
4154 * eventually. This function then waits for all managed threads to
4156 * It is not necesseray anymore to execute managed code in a subthread,
4157 * so this function should not be used anymore by default: just
4158 * execute the code and then call mono_thread_manage ().
4161 mono_runtime_exec_managed_code (MonoDomain *domain,
4162 MonoMainThreadFunc main_func,
4165 mono_thread_create (domain, main_func, main_args);
4167 mono_thread_manage ();
4171 * Execute a standard Main() method (args doesn't contain the
4175 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4177 MONO_REQ_GC_UNSAFE_MODE;
4182 MonoCustomAttrInfo* cinfo;
4183 gboolean has_stathread_attribute;
4184 MonoInternalThread* thread = mono_thread_internal_current ();
4190 domain = mono_object_domain (args);
4191 if (!domain->entry_assembly) {
4193 MonoAssembly *assembly;
4195 assembly = method->klass->image->assembly;
4196 domain->entry_assembly = assembly;
4197 /* Domains created from another domain already have application_base and configuration_file set */
4198 if (domain->setup->application_base == NULL) {
4199 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4202 if (domain->setup->configuration_file == NULL) {
4203 str = g_strconcat (assembly->image->name, ".config", NULL);
4204 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4206 mono_domain_set_options_from_config (domain);
4210 cinfo = mono_custom_attrs_from_method (method);
4212 static MonoClass *stathread_attribute = NULL;
4213 if (!stathread_attribute)
4214 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4215 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4217 mono_custom_attrs_free (cinfo);
4219 has_stathread_attribute = FALSE;
4221 if (has_stathread_attribute) {
4222 thread->apartment_state = ThreadApartmentState_STA;
4224 thread->apartment_state = ThreadApartmentState_MTA;
4226 mono_thread_init_apartment_state ();
4228 /* FIXME: check signature of method */
4229 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4231 res = mono_runtime_invoke (method, NULL, pa, exc);
4233 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4237 mono_environment_exitcode_set (rval);
4239 mono_runtime_invoke (method, NULL, pa, exc);
4243 /* If the return type of Main is void, only
4244 * set the exitcode if an exception was thrown
4245 * (we don't want to blow away an
4246 * explicitly-set exit code)
4249 mono_environment_exitcode_set (rval);
4257 * mono_install_runtime_invoke:
4258 * @func: Function to install
4260 * This is a VM internal routine
4263 mono_install_runtime_invoke (MonoInvokeFunc func)
4265 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4270 * mono_runtime_invoke_array:
4271 * @method: method to invoke
4272 * @obJ: object instance
4273 * @params: arguments to the method
4274 * @exc: exception information.
4276 * Invokes the method represented by @method on the object @obj.
4278 * obj is the 'this' pointer, it should be NULL for static
4279 * methods, a MonoObject* for object instances and a pointer to
4280 * the value type for value types.
4282 * The params array contains the arguments to the method with the
4283 * same convention: MonoObject* pointers for object instances and
4284 * pointers to the value type otherwise. The _invoke_array
4285 * variant takes a C# object[] as the params argument (MonoArray
4286 * *params): in this case the value types are boxed inside the
4287 * respective reference representation.
4289 * From unmanaged code you'll usually use the
4290 * mono_runtime_invoke() variant.
4292 * Note that this function doesn't handle virtual methods for
4293 * you, it will exec the exact method you pass: we still need to
4294 * expose a function to lookup the derived class implementation
4295 * of a virtual method (there are examples of this in the code,
4298 * You can pass NULL as the exc argument if you don't want to
4299 * catch exceptions, otherwise, *exc will be set to the exception
4300 * thrown, if any. if an exception is thrown, you can't use the
4301 * MonoObject* result from the function.
4303 * If the method returns a value type, it is boxed in an object
4307 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4310 MONO_REQ_GC_UNSAFE_MODE;
4313 MonoMethodSignature *sig = mono_method_signature (method);
4314 gpointer *pa = NULL;
4317 gboolean has_byref_nullables = FALSE;
4319 if (NULL != params) {
4320 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4321 for (i = 0; i < mono_array_length (params); i++) {
4322 MonoType *t = sig->params [i];
4328 case MONO_TYPE_BOOLEAN:
4331 case MONO_TYPE_CHAR:
4340 case MONO_TYPE_VALUETYPE:
4341 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4342 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4343 pa [i] = mono_array_get (params, MonoObject*, i);
4345 has_byref_nullables = TRUE;
4347 /* MS seems to create the objects if a null is passed in */
4348 if (!mono_array_get (params, MonoObject*, i))
4349 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4353 * We can't pass the unboxed vtype byref to the callee, since
4354 * that would mean the callee would be able to modify boxed
4355 * primitive types. So we (and MS) make a copy of the boxed
4356 * object, pass that to the callee, and replace the original
4357 * boxed object in the arg array with the copy.
4359 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4360 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4361 mono_array_setref (params, i, copy);
4364 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4367 case MONO_TYPE_STRING:
4368 case MONO_TYPE_OBJECT:
4369 case MONO_TYPE_CLASS:
4370 case MONO_TYPE_ARRAY:
4371 case MONO_TYPE_SZARRAY:
4373 pa [i] = mono_array_addr (params, MonoObject*, i);
4374 // FIXME: I need to check this code path
4376 pa [i] = mono_array_get (params, MonoObject*, i);
4378 case MONO_TYPE_GENERICINST:
4380 t = &t->data.generic_class->container_class->this_arg;
4382 t = &t->data.generic_class->container_class->byval_arg;
4384 case MONO_TYPE_PTR: {
4387 /* The argument should be an IntPtr */
4388 arg = mono_array_get (params, MonoObject*, i);
4392 g_assert (arg->vtable->klass == mono_defaults.int_class);
4393 pa [i] = ((MonoIntPtr*)arg)->m_value;
4398 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4403 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4406 if (mono_class_is_nullable (method->klass)) {
4407 /* Need to create a boxed vtype instead */
4413 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4417 obj = mono_object_new (mono_domain_get (), method->klass);
4418 g_assert (obj); /*maybe we should raise a TLE instead?*/
4419 #ifndef DISABLE_REMOTING
4420 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4421 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4424 if (method->klass->valuetype)
4425 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4428 } else if (method->klass->valuetype) {
4429 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4432 mono_runtime_invoke (method, o, pa, exc);
4433 return (MonoObject *)obj;
4435 if (mono_class_is_nullable (method->klass)) {
4436 MonoObject *nullable;
4438 /* Convert the unboxed vtype into a Nullable structure */
4439 nullable = mono_object_new (mono_domain_get (), method->klass);
4441 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4442 obj = mono_object_unbox (nullable);
4445 /* obj must be already unboxed if needed */
4446 res = mono_runtime_invoke (method, obj, pa, exc);
4448 if (sig->ret->type == MONO_TYPE_PTR) {
4449 MonoClass *pointer_class;
4450 static MonoMethod *box_method;
4452 MonoObject *box_exc;
4455 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4456 * convert it to a Pointer object.
4458 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4460 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4462 g_assert (res->vtable->klass == mono_defaults.int_class);
4463 box_args [0] = ((MonoIntPtr*)res)->m_value;
4464 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4465 mono_error_raise_exception (&error); /* FIXME don't raise here */
4467 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4468 g_assert (!box_exc);
4471 if (has_byref_nullables) {
4473 * The runtime invoke wrapper already converted byref nullables back,
4474 * and stored them in pa, we just need to copy them back to the
4477 for (i = 0; i < mono_array_length (params); i++) {
4478 MonoType *t = sig->params [i];
4480 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4481 mono_array_setref (params, i, pa [i]);
4491 * @klass: the class of the object that we want to create
4493 * Returns: a newly created object whose definition is
4494 * looked up using @klass. This will not invoke any constructors,
4495 * so the consumer of this routine has to invoke any constructors on
4496 * its own to initialize the object.
4498 * It returns NULL on failure.
4501 mono_object_new (MonoDomain *domain, MonoClass *klass)
4503 MONO_REQ_GC_UNSAFE_MODE;
4507 vtable = mono_class_vtable (domain, klass);
4512 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4513 mono_error_raise_exception (&error); /* FIXME don't raise here */
4519 * mono_object_new_pinned:
4521 * Same as mono_object_new, but the returned object will be pinned.
4522 * For SGEN, these objects will only be freed at appdomain unload.
4525 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4527 MONO_REQ_GC_UNSAFE_MODE;
4531 mono_error_init (error);
4533 vtable = mono_class_vtable (domain, klass);
4534 g_assert (vtable); /* FIXME don't swallow the error */
4536 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4538 if (G_UNLIKELY (!o))
4539 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4540 else if (G_UNLIKELY (vtable->klass->has_finalize))
4541 mono_object_register_finalizer (o);
4547 * mono_object_new_specific:
4548 * @vtable: the vtable of the object that we want to create
4550 * Returns: A newly created object with class and domain specified
4554 mono_object_new_specific (MonoVTable *vtable)
4557 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4558 mono_error_raise_exception (&error);
4564 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4566 MONO_REQ_GC_UNSAFE_MODE;
4570 mono_error_init (error);
4572 /* check for is_com_object for COM Interop */
4573 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4576 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4579 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4582 mono_class_init (klass);
4584 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4586 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4589 vtable->domain->create_proxy_for_type_method = im;
4592 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4593 if (!mono_error_ok (error))
4596 o = mono_runtime_invoke (im, NULL, pa, NULL);
4597 if (o != NULL) return o;
4600 return mono_object_new_alloc_specific_checked (vtable, error);
4604 ves_icall_object_new_specific (MonoVTable *vtable)
4607 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4608 mono_error_raise_exception (&error);
4614 mono_object_new_alloc_specific (MonoVTable *vtable)
4617 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4618 mono_error_raise_exception (&error);
4624 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4626 MONO_REQ_GC_UNSAFE_MODE;
4630 mono_error_init (error);
4632 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4634 if (G_UNLIKELY (!o))
4635 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4636 else if (G_UNLIKELY (vtable->klass->has_finalize))
4637 mono_object_register_finalizer (o);
4643 mono_object_new_fast (MonoVTable *vtable)
4646 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4647 mono_error_raise_exception (&error);
4653 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4655 MONO_REQ_GC_UNSAFE_MODE;
4659 mono_error_init (error);
4661 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4663 if (G_UNLIKELY (!o))
4664 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4670 ves_icall_object_new_fast (MonoVTable *vtable)
4673 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4674 mono_error_raise_exception (&error);
4680 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4682 MONO_REQ_GC_UNSAFE_MODE;
4686 mono_error_init (error);
4688 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4690 if (G_UNLIKELY (!o))
4691 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4692 else if (G_UNLIKELY (vtable->klass->has_finalize))
4693 mono_object_register_finalizer (o);
4699 * mono_class_get_allocation_ftn:
4701 * @for_box: the object will be used for boxing
4702 * @pass_size_in_words:
4704 * Return the allocation function appropriate for the given class.
4708 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4710 MONO_REQ_GC_NEUTRAL_MODE;
4712 *pass_size_in_words = FALSE;
4714 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4715 return ves_icall_object_new_specific;
4717 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4719 return ves_icall_object_new_fast;
4722 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4723 * of the overhead of parameter passing.
4726 *pass_size_in_words = TRUE;
4727 #ifdef GC_REDIRECT_TO_LOCAL
4728 return GC_local_gcj_fast_malloc;
4730 return GC_gcj_fast_malloc;
4735 return ves_icall_object_new_specific;
4739 * mono_object_new_from_token:
4740 * @image: Context where the type_token is hosted
4741 * @token: a token of the type that we want to create
4743 * Returns: A newly created object whose definition is
4744 * looked up using @token in the @image image
4747 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4749 MONO_REQ_GC_UNSAFE_MODE;
4754 klass = mono_class_get_checked (image, token, &error);
4755 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4757 return mono_object_new (domain, klass);
4762 * mono_object_clone:
4763 * @obj: the object to clone
4765 * Returns: A newly created object who is a shallow copy of @obj
4768 mono_object_clone (MonoObject *obj)
4771 MonoObject *o = mono_object_clone_checked (obj, &error);
4772 mono_error_raise_exception (&error);
4778 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4780 MONO_REQ_GC_UNSAFE_MODE;
4785 mono_error_init (error);
4787 size = obj->vtable->klass->instance_size;
4789 if (obj->vtable->klass->rank)
4790 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4792 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4794 if (G_UNLIKELY (!o)) {
4795 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4799 /* If the object doesn't contain references this will do a simple memmove. */
4800 mono_gc_wbarrier_object_copy (o, obj);
4802 if (obj->vtable->klass->has_finalize)
4803 mono_object_register_finalizer (o);
4808 * mono_array_full_copy:
4809 * @src: source array to copy
4810 * @dest: destination array
4812 * Copies the content of one array to another with exactly the same type and size.
4815 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4817 MONO_REQ_GC_UNSAFE_MODE;
4820 MonoClass *klass = src->obj.vtable->klass;
4822 g_assert (klass == dest->obj.vtable->klass);
4824 size = mono_array_length (src);
4825 g_assert (size == mono_array_length (dest));
4826 size *= mono_array_element_size (klass);
4828 if (klass->element_class->valuetype) {
4829 if (klass->element_class->has_references)
4830 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4832 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4834 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4837 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4842 * mono_array_clone_in_domain:
4843 * @domain: the domain in which the array will be cloned into
4844 * @array: the array to clone
4846 * This routine returns a copy of the array that is hosted on the
4847 * specified MonoDomain.
4850 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4852 MONO_REQ_GC_UNSAFE_MODE;
4858 MonoClass *klass = array->obj.vtable->klass;
4860 if (array->bounds == NULL) {
4861 size = mono_array_length (array);
4862 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
4863 mono_error_raise_exception (&error); /* FIXME don't raise here */
4865 size *= mono_array_element_size (klass);
4867 if (klass->element_class->valuetype) {
4868 if (klass->element_class->has_references)
4869 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4871 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4873 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4876 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4881 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4882 size = mono_array_element_size (klass);
4883 for (i = 0; i < klass->rank; ++i) {
4884 sizes [i] = array->bounds [i].length;
4885 size *= array->bounds [i].length;
4886 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4888 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
4889 mono_error_raise_exception (&error); /* FIXME don't raise here */
4891 if (klass->element_class->valuetype) {
4892 if (klass->element_class->has_references)
4893 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4895 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4897 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4900 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4908 * @array: the array to clone
4910 * Returns: A newly created array who is a shallow copy of @array
4913 mono_array_clone (MonoArray *array)
4915 MONO_REQ_GC_UNSAFE_MODE;
4917 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4920 /* helper macros to check for overflow when calculating the size of arrays */
4921 #ifdef MONO_BIG_ARRAYS
4922 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4923 #define MYGUINT_MAX MYGUINT64_MAX
4924 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4925 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4926 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4927 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4928 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4930 #define MYGUINT32_MAX 4294967295U
4931 #define MYGUINT_MAX MYGUINT32_MAX
4932 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4933 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4934 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4935 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4936 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4940 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4942 MONO_REQ_GC_NEUTRAL_MODE;
4946 byte_len = mono_array_element_size (klass);
4947 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4950 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4952 byte_len += MONO_SIZEOF_MONO_ARRAY;
4960 * mono_array_new_full:
4961 * @domain: domain where the object is created
4962 * @array_class: array class
4963 * @lengths: lengths for each dimension in the array
4964 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4966 * This routine creates a new array objects with the given dimensions,
4967 * lower bounds and type.
4970 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4973 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
4974 mono_error_raise_exception (&error);
4980 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
4982 MONO_REQ_GC_UNSAFE_MODE;
4984 uintptr_t byte_len = 0, len, bounds_size;
4987 MonoArrayBounds *bounds;
4991 mono_error_init (error);
4993 if (!array_class->inited)
4994 mono_class_init (array_class);
4998 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4999 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5001 if (len > MONO_ARRAY_MAX_INDEX) {
5002 mono_error_set_generic_error (error, "System", "OverflowException", "");
5007 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5009 for (i = 0; i < array_class->rank; ++i) {
5010 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5011 mono_error_set_generic_error (error, "System", "OverflowException", "");
5014 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5015 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5022 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5023 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5029 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5030 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5033 byte_len = (byte_len + 3) & ~3;
5034 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5035 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5038 byte_len += bounds_size;
5041 * Following three lines almost taken from mono_object_new ():
5042 * they need to be kept in sync.
5044 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5046 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5048 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5050 if (G_UNLIKELY (!o)) {
5051 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5055 array = (MonoArray*)o;
5057 bounds = array->bounds;
5060 for (i = 0; i < array_class->rank; ++i) {
5061 bounds [i].length = lengths [i];
5063 bounds [i].lower_bound = lower_bounds [i];
5072 * @domain: domain where the object is created
5073 * @eclass: element class
5074 * @n: number of array elements
5076 * This routine creates a new szarray with @n elements of type @eclass.
5079 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5081 MONO_REQ_GC_UNSAFE_MODE;
5087 ac = mono_array_class_get (eclass, 1);
5090 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5091 mono_error_raise_exception (&error); /* FIXME don't raise here */
5097 * mono_array_new_specific:
5098 * @vtable: a vtable in the appropriate domain for an initialized class
5099 * @n: number of array elements
5101 * This routine is a fast alternative to mono_array_new() for code which
5102 * can be sure about the domain it operates in.
5105 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5108 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5109 mono_error_raise_exception (&error); /* FIXME don't raise here */
5115 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5117 MONO_REQ_GC_UNSAFE_MODE;
5122 mono_error_init (error);
5124 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5125 mono_error_set_generic_error (error, "System", "OverflowException", "");
5129 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5130 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5133 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5135 if (G_UNLIKELY (!o)) {
5136 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5140 return (MonoArray*)o;
5144 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5147 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5148 mono_error_raise_exception (&error);
5154 * mono_string_new_utf16:
5155 * @text: a pointer to an utf16 string
5156 * @len: the length of the string
5158 * Returns: A newly created string object which contains @text.
5161 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5163 MONO_REQ_GC_UNSAFE_MODE;
5168 s = mono_string_new_size_checked (domain, len, &error);
5169 mono_error_raise_exception (&error); /* FIXME don't raise here */
5171 memcpy (mono_string_chars (s), text, len * 2);
5177 * mono_string_new_utf32:
5178 * @text: a pointer to an utf32 string
5179 * @len: the length of the string
5181 * Returns: A newly created string object which contains @text.
5184 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5186 MONO_REQ_GC_UNSAFE_MODE;
5190 mono_unichar2 *utf16_output = NULL;
5191 gint32 utf16_len = 0;
5192 GError *gerror = NULL;
5193 glong items_written;
5195 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5198 g_error_free (gerror);
5200 while (utf16_output [utf16_len]) utf16_len++;
5202 s = mono_string_new_size_checked (domain, utf16_len, &error);
5203 mono_error_raise_exception (&error); /* FIXME don't raise here */
5205 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5207 g_free (utf16_output);
5213 * mono_string_new_size:
5214 * @text: a pointer to an utf16 string
5215 * @len: the length of the string
5217 * Returns: A newly created string object of @len
5220 mono_string_new_size (MonoDomain *domain, gint32 len)
5223 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5224 mono_error_raise_exception (&error);
5230 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5232 MONO_REQ_GC_UNSAFE_MODE;
5238 mono_error_init (error);
5240 /* check for overflow */
5241 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5242 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5246 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5247 g_assert (size > 0);
5249 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5252 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5254 if (G_UNLIKELY (!s)) {
5255 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5263 * mono_string_new_len:
5264 * @text: a pointer to an utf8 string
5265 * @length: number of bytes in @text to consider
5267 * Returns: A newly created string object which contains @text.
5270 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5272 MONO_REQ_GC_UNSAFE_MODE;
5274 GError *error = NULL;
5275 MonoString *o = NULL;
5277 glong items_written;
5279 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5282 o = mono_string_new_utf16 (domain, ut, items_written);
5284 g_error_free (error);
5293 * @text: a pointer to an utf8 string
5295 * Returns: A newly created string object which contains @text.
5298 mono_string_new (MonoDomain *domain, const char *text)
5300 MONO_REQ_GC_UNSAFE_MODE;
5302 GError *error = NULL;
5303 MonoString *o = NULL;
5305 glong items_written;
5310 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5313 o = mono_string_new_utf16 (domain, ut, items_written);
5315 g_error_free (error);
5318 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5324 MonoString *o = NULL;
5326 if (!g_utf8_validate (text, -1, &end))
5329 len = g_utf8_strlen (text, -1);
5330 o = mono_string_new_size_checked (domain, len, &error);
5331 mono_error_raise_exception (&error); /* FIXME don't raise here */
5332 str = mono_string_chars (o);
5334 while (text < end) {
5335 *str++ = g_utf8_get_char (text);
5336 text = g_utf8_next_char (text);
5343 * mono_string_new_wrapper:
5344 * @text: pointer to utf8 characters.
5346 * Helper function to create a string object from @text in the current domain.
5349 mono_string_new_wrapper (const char *text)
5351 MONO_REQ_GC_UNSAFE_MODE;
5353 MonoDomain *domain = mono_domain_get ();
5356 return mono_string_new (domain, text);
5363 * @class: the class of the value
5364 * @value: a pointer to the unboxed data
5366 * Returns: A newly created object which contains @value.
5369 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5371 MONO_REQ_GC_UNSAFE_MODE;
5378 g_assert (klass->valuetype);
5379 if (mono_class_is_nullable (klass))
5380 return mono_nullable_box ((guint8 *)value, klass);
5382 vtable = mono_class_vtable (domain, klass);
5385 size = mono_class_instance_size (klass);
5386 res = mono_object_new_alloc_specific_checked (vtable, &error);
5387 mono_error_raise_exception (&error); /* FIXME don't raise here */
5389 size = size - sizeof (MonoObject);
5392 g_assert (size == mono_class_value_size (klass, NULL));
5393 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5395 #if NO_UNALIGNED_ACCESS
5396 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5400 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5403 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5406 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5409 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5412 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5416 if (klass->has_finalize)
5417 mono_object_register_finalizer (res);
5423 * @dest: destination pointer
5424 * @src: source pointer
5425 * @klass: a valuetype class
5427 * Copy a valuetype from @src to @dest. This function must be used
5428 * when @klass contains references fields.
5431 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5433 MONO_REQ_GC_UNSAFE_MODE;
5435 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5439 * mono_value_copy_array:
5440 * @dest: destination array
5441 * @dest_idx: index in the @dest array
5442 * @src: source pointer
5443 * @count: number of items
5445 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5446 * This function must be used when @klass contains references fields.
5447 * Overlap is handled.
5450 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5452 MONO_REQ_GC_UNSAFE_MODE;
5454 int size = mono_array_element_size (dest->obj.vtable->klass);
5455 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5456 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5457 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5461 * mono_object_get_domain:
5462 * @obj: object to query
5464 * Returns: the MonoDomain where the object is hosted
5467 mono_object_get_domain (MonoObject *obj)
5469 MONO_REQ_GC_UNSAFE_MODE;
5471 return mono_object_domain (obj);
5475 * mono_object_get_class:
5476 * @obj: object to query
5478 * Returns: the MonOClass of the object.
5481 mono_object_get_class (MonoObject *obj)
5483 MONO_REQ_GC_UNSAFE_MODE;
5485 return mono_object_class (obj);
5488 * mono_object_get_size:
5489 * @o: object to query
5491 * Returns: the size, in bytes, of @o
5494 mono_object_get_size (MonoObject* o)
5496 MONO_REQ_GC_UNSAFE_MODE;
5498 MonoClass* klass = mono_object_class (o);
5499 if (klass == mono_defaults.string_class) {
5500 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5501 } else if (o->vtable->rank) {
5502 MonoArray *array = (MonoArray*)o;
5503 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5504 if (array->bounds) {
5507 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5511 return mono_class_instance_size (klass);
5516 * mono_object_unbox:
5517 * @obj: object to unbox
5519 * Returns: a pointer to the start of the valuetype boxed in this
5522 * This method will assert if the object passed is not a valuetype.
5525 mono_object_unbox (MonoObject *obj)
5527 MONO_REQ_GC_UNSAFE_MODE;
5529 /* add assert for valuetypes? */
5530 g_assert (obj->vtable->klass->valuetype);
5531 return ((char*)obj) + sizeof (MonoObject);
5535 * mono_object_isinst:
5537 * @klass: a pointer to a class
5539 * Returns: @obj if @obj is derived from @klass
5542 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5544 MONO_REQ_GC_UNSAFE_MODE;
5547 mono_class_init (klass);
5549 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5550 return mono_object_isinst_mbyref (obj, klass);
5555 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5559 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5561 MONO_REQ_GC_UNSAFE_MODE;
5571 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5572 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5576 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5577 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5580 MonoClass *oklass = vt->klass;
5581 if (mono_class_is_transparent_proxy (oklass))
5582 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5584 mono_class_setup_supertypes (klass);
5585 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5588 #ifndef DISABLE_REMOTING
5589 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5591 MonoDomain *domain = mono_domain_get ();
5593 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5594 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5595 MonoMethod *im = NULL;
5598 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5600 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5601 im = mono_object_get_virtual_method (rp, im);
5604 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5605 mono_error_raise_exception (&error); /* FIXME don't raise here */
5608 res = mono_runtime_invoke (im, rp, pa, NULL);
5610 if (*(MonoBoolean *) mono_object_unbox(res)) {
5611 /* Update the vtable of the remote type, so it can safely cast to this new type */
5612 mono_upgrade_remote_class (domain, obj, klass);
5616 #endif /* DISABLE_REMOTING */
5621 * mono_object_castclass_mbyref:
5623 * @klass: a pointer to a class
5625 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5628 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5630 MONO_REQ_GC_UNSAFE_MODE;
5632 if (!obj) return NULL;
5633 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5635 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5637 "InvalidCastException"));
5642 MonoDomain *orig_domain;
5648 str_lookup (MonoDomain *domain, gpointer user_data)
5650 MONO_REQ_GC_UNSAFE_MODE;
5652 LDStrInfo *info = (LDStrInfo *)user_data;
5653 if (info->res || domain == info->orig_domain)
5655 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5659 mono_string_get_pinned (MonoString *str, MonoError *error)
5661 MONO_REQ_GC_UNSAFE_MODE;
5663 mono_error_init (error);
5665 /* We only need to make a pinned version of a string if this is a moving GC */
5666 if (!mono_gc_is_moving ())
5670 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5671 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5673 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5674 news->length = mono_string_length (str);
5676 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5682 mono_string_is_interned_lookup (MonoString *str, int insert)
5684 MONO_REQ_GC_UNSAFE_MODE;
5687 MonoGHashTable *ldstr_table;
5688 MonoString *s, *res;
5691 domain = ((MonoObject *)str)->vtable->domain;
5692 ldstr_table = domain->ldstr_table;
5694 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5700 /* Allocate outside the lock */
5702 s = mono_string_get_pinned (str, &error);
5703 mono_error_raise_exception (&error); /* FIXME don't raise here */
5706 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5711 mono_g_hash_table_insert (ldstr_table, s, s);
5716 LDStrInfo ldstr_info;
5717 ldstr_info.orig_domain = domain;
5718 ldstr_info.ins = str;
5719 ldstr_info.res = NULL;
5721 mono_domain_foreach (str_lookup, &ldstr_info);
5722 if (ldstr_info.res) {
5724 * the string was already interned in some other domain:
5725 * intern it in the current one as well.
5727 mono_g_hash_table_insert (ldstr_table, str, str);
5737 * mono_string_is_interned:
5738 * @o: String to probe
5740 * Returns whether the string has been interned.
5743 mono_string_is_interned (MonoString *o)
5745 MONO_REQ_GC_UNSAFE_MODE;
5747 return mono_string_is_interned_lookup (o, FALSE);
5751 * mono_string_intern:
5752 * @o: String to intern
5754 * Interns the string passed.
5755 * Returns: The interned string.
5758 mono_string_intern (MonoString *str)
5760 MONO_REQ_GC_UNSAFE_MODE;
5762 return mono_string_is_interned_lookup (str, TRUE);
5767 * @domain: the domain where the string will be used.
5768 * @image: a metadata context
5769 * @idx: index into the user string table.
5771 * Implementation for the ldstr opcode.
5772 * Returns: a loaded string from the @image/@idx combination.
5775 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5777 MONO_REQ_GC_UNSAFE_MODE;
5779 if (image->dynamic) {
5780 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5783 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5784 return NULL; /*FIXME we should probably be raising an exception here*/
5785 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5790 * mono_ldstr_metadata_sig
5791 * @domain: the domain for the string
5792 * @sig: the signature of a metadata string
5794 * Returns: a MonoString for a string stored in the metadata
5797 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5799 MONO_REQ_GC_UNSAFE_MODE;
5802 const char *str = sig;
5803 MonoString *o, *interned;
5806 len2 = mono_metadata_decode_blob_size (str, &str);
5809 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5810 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5813 guint16 *p2 = (guint16*)mono_string_chars (o);
5814 for (i = 0; i < len2; ++i) {
5815 *p2 = GUINT16_FROM_LE (*p2);
5821 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5824 return interned; /* o will get garbage collected */
5826 o = mono_string_get_pinned (o, &error);
5827 mono_error_raise_exception (&error); /* FIXME don't raise here */
5830 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5832 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5842 * mono_string_to_utf8:
5843 * @s: a System.String
5845 * Returns the UTF8 representation for @s.
5846 * The resulting buffer needs to be freed with mono_free().
5848 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5851 mono_string_to_utf8 (MonoString *s)
5853 MONO_REQ_GC_UNSAFE_MODE;
5856 char *result = mono_string_to_utf8_checked (s, &error);
5858 if (!mono_error_ok (&error))
5859 mono_error_raise_exception (&error);
5864 * mono_string_to_utf8_checked:
5865 * @s: a System.String
5866 * @error: a MonoError.
5868 * Converts a MonoString to its UTF8 representation. May fail; check
5869 * @error to determine whether the conversion was successful.
5870 * The resulting buffer should be freed with mono_free().
5873 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5875 MONO_REQ_GC_UNSAFE_MODE;
5879 GError *gerror = NULL;
5881 mono_error_init (error);
5887 return g_strdup ("");
5889 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5891 mono_error_set_argument (error, "string", "%s", gerror->message);
5892 g_error_free (gerror);
5895 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5896 if (s->length > written) {
5897 /* allocate the total length and copy the part of the string that has been converted */
5898 char *as2 = (char *)g_malloc0 (s->length);
5899 memcpy (as2, as, written);
5908 * mono_string_to_utf8_ignore:
5911 * Converts a MonoString to its UTF8 representation. Will ignore
5912 * invalid surrogate pairs.
5913 * The resulting buffer should be freed with mono_free().
5917 mono_string_to_utf8_ignore (MonoString *s)
5919 MONO_REQ_GC_UNSAFE_MODE;
5928 return g_strdup ("");
5930 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5932 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5933 if (s->length > written) {
5934 /* allocate the total length and copy the part of the string that has been converted */
5935 char *as2 = (char *)g_malloc0 (s->length);
5936 memcpy (as2, as, written);
5945 * mono_string_to_utf8_image_ignore:
5946 * @s: a System.String
5948 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5951 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5953 MONO_REQ_GC_UNSAFE_MODE;
5955 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5959 * mono_string_to_utf8_mp_ignore:
5960 * @s: a System.String
5962 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5965 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5967 MONO_REQ_GC_UNSAFE_MODE;
5969 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5974 * mono_string_to_utf16:
5977 * Return an null-terminated array of the utf-16 chars
5978 * contained in @s. The result must be freed with g_free().
5979 * This is a temporary helper until our string implementation
5980 * is reworked to always include the null terminating char.
5983 mono_string_to_utf16 (MonoString *s)
5985 MONO_REQ_GC_UNSAFE_MODE;
5992 as = (char *)g_malloc ((s->length * 2) + 2);
5993 as [(s->length * 2)] = '\0';
5994 as [(s->length * 2) + 1] = '\0';
5997 return (gunichar2 *)(as);
6000 memcpy (as, mono_string_chars(s), s->length * 2);
6001 return (gunichar2 *)(as);
6005 * mono_string_to_utf32:
6008 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6009 * contained in @s. The result must be freed with g_free().
6012 mono_string_to_utf32 (MonoString *s)
6014 MONO_REQ_GC_UNSAFE_MODE;
6016 mono_unichar4 *utf32_output = NULL;
6017 GError *error = NULL;
6018 glong items_written;
6023 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6026 g_error_free (error);
6028 return utf32_output;
6032 * mono_string_from_utf16:
6033 * @data: the UTF16 string (LPWSTR) to convert
6035 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6037 * Returns: a MonoString.
6040 mono_string_from_utf16 (gunichar2 *data)
6042 MONO_REQ_GC_UNSAFE_MODE;
6044 MonoDomain *domain = mono_domain_get ();
6050 while (data [len]) len++;
6052 return mono_string_new_utf16 (domain, data, len);
6056 * mono_string_from_utf32:
6057 * @data: the UTF32 string (LPWSTR) to convert
6059 * Converts a UTF32 (UCS-4)to a MonoString.
6061 * Returns: a MonoString.
6064 mono_string_from_utf32 (mono_unichar4 *data)
6066 MONO_REQ_GC_UNSAFE_MODE;
6068 MonoString* result = NULL;
6069 mono_unichar2 *utf16_output = NULL;
6070 GError *error = NULL;
6071 glong items_written;
6077 while (data [len]) len++;
6079 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6082 g_error_free (error);
6084 result = mono_string_from_utf16 (utf16_output);
6085 g_free (utf16_output);
6090 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6092 MONO_REQ_GC_UNSAFE_MODE;
6099 r = mono_string_to_utf8_ignore (s);
6101 r = mono_string_to_utf8_checked (s, error);
6102 if (!mono_error_ok (error))
6109 len = strlen (r) + 1;
6111 mp_s = (char *)mono_mempool_alloc (mp, len);
6113 mp_s = (char *)mono_image_alloc (image, len);
6115 memcpy (mp_s, r, len);
6123 * mono_string_to_utf8_image:
6124 * @s: a System.String
6126 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6129 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6131 MONO_REQ_GC_UNSAFE_MODE;
6133 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6137 * mono_string_to_utf8_mp:
6138 * @s: a System.String
6140 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6143 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6145 MONO_REQ_GC_UNSAFE_MODE;
6147 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6151 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6154 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6156 eh_callbacks = *cbs;
6159 MonoRuntimeExceptionHandlingCallbacks *
6160 mono_get_eh_callbacks (void)
6162 return &eh_callbacks;
6166 * mono_raise_exception:
6167 * @ex: exception object
6169 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6172 mono_raise_exception (MonoException *ex)
6174 MONO_REQ_GC_UNSAFE_MODE;
6177 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6178 * that will cause gcc to omit the function epilog, causing problems when
6179 * the JIT tries to walk the stack, since the return address on the stack
6180 * will point into the next function in the executable, not this one.
6182 eh_callbacks.mono_raise_exception (ex);
6186 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6188 MONO_REQ_GC_UNSAFE_MODE;
6190 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6194 * mono_wait_handle_new:
6195 * @domain: Domain where the object will be created
6196 * @handle: Handle for the wait handle
6198 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6201 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6203 MONO_REQ_GC_UNSAFE_MODE;
6205 MonoWaitHandle *res;
6206 gpointer params [1];
6207 static MonoMethod *handle_set;
6209 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6211 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6213 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6215 params [0] = &handle;
6216 mono_runtime_invoke (handle_set, res, params, NULL);
6222 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6224 MONO_REQ_GC_UNSAFE_MODE;
6226 static MonoClassField *f_os_handle;
6227 static MonoClassField *f_safe_handle;
6229 if (!f_os_handle && !f_safe_handle) {
6230 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6231 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6236 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6240 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6247 mono_runtime_capture_context (MonoDomain *domain)
6249 MONO_REQ_GC_UNSAFE_MODE;
6251 RuntimeInvokeFunction runtime_invoke;
6253 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6254 MonoMethod *method = mono_get_context_capture_method ();
6255 MonoMethod *wrapper;
6258 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6259 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6260 domain->capture_context_method = mono_compile_method (method);
6263 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6265 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6268 * mono_async_result_new:
6269 * @domain:domain where the object will be created.
6270 * @handle: wait handle.
6271 * @state: state to pass to AsyncResult
6272 * @data: C closure data.
6274 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6275 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6279 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6281 MONO_REQ_GC_UNSAFE_MODE;
6283 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6284 MonoObject *context = mono_runtime_capture_context (domain);
6285 /* we must capture the execution context from the original thread */
6287 MONO_OBJECT_SETREF (res, execution_context, context);
6288 /* note: result may be null if the flow is suppressed */
6291 res->data = (void **)data;
6292 MONO_OBJECT_SETREF (res, object_data, object_data);
6293 MONO_OBJECT_SETREF (res, async_state, state);
6295 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6297 res->sync_completed = FALSE;
6298 res->completed = FALSE;
6304 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6306 MONO_REQ_GC_UNSAFE_MODE;
6312 g_assert (ares->async_delegate);
6314 ac = (MonoAsyncCall*) ares->object_data;
6316 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6318 gpointer wait_event = NULL;
6320 ac->msg->exc = NULL;
6321 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6322 MONO_OBJECT_SETREF (ac, res, res);
6324 mono_monitor_enter ((MonoObject*) ares);
6325 ares->completed = 1;
6327 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6328 mono_monitor_exit ((MonoObject*) ares);
6330 if (wait_event != NULL)
6331 SetEvent (wait_event);
6333 if (ac->cb_method) {
6334 /* we swallow the excepton as it is the behavior on .NET */
6335 MonoObject *exc = NULL;
6336 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6338 mono_unhandled_exception (exc);
6346 mono_message_init (MonoDomain *domain,
6347 MonoMethodMessage *this_obj,
6348 MonoReflectionMethod *method,
6349 MonoArray *out_args)
6351 MONO_REQ_GC_UNSAFE_MODE;
6353 static MonoClass *object_array_klass;
6354 static MonoClass *byte_array_klass;
6355 static MonoClass *string_array_klass;
6357 MonoMethodSignature *sig = mono_method_signature (method->method);
6364 if (!object_array_klass) {
6367 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6369 byte_array_klass = klass;
6371 klass = mono_array_class_get (mono_defaults.string_class, 1);
6373 string_array_klass = klass;
6375 klass = mono_array_class_get (mono_defaults.object_class, 1);
6378 mono_atomic_store_release (&object_array_klass, klass);
6381 MONO_OBJECT_SETREF (this_obj, method, method);
6383 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6384 mono_error_raise_exception (&error); /* FIXME don't raise here */
6386 MONO_OBJECT_SETREF (this_obj, args, arr);
6388 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6389 mono_error_raise_exception (&error); /* FIXME don't raise here */
6391 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6393 this_obj->async_result = NULL;
6394 this_obj->call_type = CallType_Sync;
6396 names = g_new (char *, sig->param_count);
6397 mono_method_get_param_names (method->method, (const char **) names);
6399 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6400 mono_error_raise_exception (&error); /* FIXME don't raise here */
6402 MONO_OBJECT_SETREF (this_obj, names, arr);
6404 for (i = 0; i < sig->param_count; i++) {
6405 name = mono_string_new (domain, names [i]);
6406 mono_array_setref (this_obj->names, i, name);
6410 for (i = 0, j = 0; i < sig->param_count; i++) {
6411 if (sig->params [i]->byref) {
6413 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6414 mono_array_setref (this_obj->args, i, arg);
6418 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6422 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6425 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6429 #ifndef DISABLE_REMOTING
6431 * mono_remoting_invoke:
6432 * @real_proxy: pointer to a RealProxy object
6433 * @msg: The MonoMethodMessage to execute
6434 * @exc: used to store exceptions
6435 * @out_args: used to store output arguments
6437 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6438 * IMessage interface and it is not trivial to extract results from there. So
6439 * we call an helper method PrivateInvoke instead of calling
6440 * RealProxy::Invoke() directly.
6442 * Returns: the result object.
6445 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6446 MonoObject **exc, MonoArray **out_args)
6448 MONO_REQ_GC_UNSAFE_MODE;
6450 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6453 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6456 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6458 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6459 real_proxy->vtable->domain->private_invoke_method = im;
6462 pa [0] = real_proxy;
6467 return mono_runtime_invoke (im, NULL, pa, exc);
6472 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6473 MonoObject **exc, MonoArray **out_args)
6475 MONO_REQ_GC_UNSAFE_MODE;
6477 static MonoClass *object_array_klass;
6481 MonoMethodSignature *sig;
6484 int i, j, outarg_count = 0;
6486 #ifndef DISABLE_REMOTING
6487 if (target && mono_object_is_transparent_proxy (target)) {
6488 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6489 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6490 target = tp->rp->unwrapped_server;
6492 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6497 domain = mono_domain_get ();
6498 method = msg->method->method;
6499 sig = mono_method_signature (method);
6501 for (i = 0; i < sig->param_count; i++) {
6502 if (sig->params [i]->byref)
6506 if (!object_array_klass) {
6509 klass = mono_array_class_get (mono_defaults.object_class, 1);
6512 mono_memory_barrier ();
6513 object_array_klass = klass;
6516 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6517 mono_error_raise_exception (&error); /* FIXME don't raise here */
6519 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6522 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6524 for (i = 0, j = 0; i < sig->param_count; i++) {
6525 if (sig->params [i]->byref) {
6527 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6528 mono_array_setref (*out_args, j, arg);
6537 * mono_object_to_string:
6539 * @exc: Any exception thrown by ToString (). May be NULL.
6541 * Returns: the result of calling ToString () on an object.
6544 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6546 MONO_REQ_GC_UNSAFE_MODE;
6548 static MonoMethod *to_string = NULL;
6555 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6557 method = mono_object_get_virtual_method (obj, to_string);
6559 // Unbox value type if needed
6560 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6561 target = mono_object_unbox (obj);
6564 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6568 * mono_print_unhandled_exception:
6569 * @exc: The exception
6571 * Prints the unhandled exception.
6574 mono_print_unhandled_exception (MonoObject *exc)
6576 MONO_REQ_GC_UNSAFE_MODE;
6579 char *message = (char*)"";
6580 gboolean free_message = FALSE;
6583 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6584 message = g_strdup ("OutOfMemoryException");
6585 free_message = TRUE;
6586 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6587 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6588 free_message = TRUE;
6591 if (((MonoException*)exc)->native_trace_ips) {
6592 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6593 free_message = TRUE;
6595 MonoObject *other_exc = NULL;
6596 str = mono_object_to_string (exc, &other_exc);
6598 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6599 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6601 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6602 original_backtrace, nested_backtrace);
6604 g_free (original_backtrace);
6605 g_free (nested_backtrace);
6606 free_message = TRUE;
6608 message = mono_string_to_utf8_checked (str, &error);
6609 if (!mono_error_ok (&error)) {
6610 mono_error_cleanup (&error);
6611 message = (char *) "";
6613 free_message = TRUE;
6620 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6621 * exc->vtable->klass->name, message);
6623 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6630 * mono_delegate_ctor:
6631 * @this: pointer to an uninitialized delegate object
6632 * @target: target object
6633 * @addr: pointer to native code
6636 * Initialize a delegate and sets a specific method, not the one
6637 * associated with addr. This is useful when sharing generic code.
6638 * In that case addr will most probably not be associated with the
6639 * correct instantiation of the method.
6642 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6644 MONO_REQ_GC_UNSAFE_MODE;
6646 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6648 g_assert (this_obj);
6651 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6654 delegate->method = method;
6656 mono_stats.delegate_creations++;
6658 #ifndef DISABLE_REMOTING
6659 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6661 method = mono_marshal_get_remoting_invoke (method);
6662 delegate->method_ptr = mono_compile_method (method);
6663 MONO_OBJECT_SETREF (delegate, target, target);
6667 delegate->method_ptr = addr;
6668 MONO_OBJECT_SETREF (delegate, target, target);
6671 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6672 if (callbacks.init_delegate)
6673 callbacks.init_delegate (delegate);
6677 * mono_delegate_ctor:
6678 * @this: pointer to an uninitialized delegate object
6679 * @target: target object
6680 * @addr: pointer to native code
6682 * This is used to initialize a delegate.
6685 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6687 MONO_REQ_GC_UNSAFE_MODE;
6689 MonoDomain *domain = mono_domain_get ();
6691 MonoMethod *method = NULL;
6695 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6697 if (!ji && domain != mono_get_root_domain ())
6698 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6700 method = mono_jit_info_get_method (ji);
6701 g_assert (!method->klass->generic_container);
6704 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6708 * mono_method_call_message_new:
6709 * @method: method to encapsulate
6710 * @params: parameters to the method
6711 * @invoke: optional, delegate invoke.
6712 * @cb: async callback delegate.
6713 * @state: state passed to the async callback.
6715 * Translates arguments pointers into a MonoMethodMessage.
6718 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6719 MonoDelegate **cb, MonoObject **state)
6721 MONO_REQ_GC_UNSAFE_MODE;
6723 MonoDomain *domain = mono_domain_get ();
6724 MonoMethodSignature *sig = mono_method_signature (method);
6725 MonoMethodMessage *msg;
6728 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6731 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6732 count = sig->param_count - 2;
6734 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6735 count = sig->param_count;
6738 for (i = 0; i < count; i++) {
6743 if (sig->params [i]->byref)
6744 vpos = *((gpointer *)params [i]);
6748 klass = mono_class_from_mono_type (sig->params [i]);
6750 if (klass->valuetype)
6751 arg = mono_value_box (domain, klass, vpos);
6753 arg = *((MonoObject **)vpos);
6755 mono_array_setref (msg->args, i, arg);
6758 if (cb != NULL && state != NULL) {
6759 *cb = *((MonoDelegate **)params [i]);
6761 *state = *((MonoObject **)params [i]);
6768 * mono_method_return_message_restore:
6770 * Restore results from message based processing back to arguments pointers
6773 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6775 MONO_REQ_GC_UNSAFE_MODE;
6777 MonoMethodSignature *sig = mono_method_signature (method);
6778 int i, j, type, size, out_len;
6780 if (out_args == NULL)
6782 out_len = mono_array_length (out_args);
6786 for (i = 0, j = 0; i < sig->param_count; i++) {
6787 MonoType *pt = sig->params [i];
6792 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6794 arg = (char *)mono_array_get (out_args, gpointer, j);
6797 g_assert (type != MONO_TYPE_VOID);
6799 if (MONO_TYPE_IS_REFERENCE (pt)) {
6800 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6803 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6804 size = mono_class_value_size (klass, NULL);
6805 if (klass->has_references)
6806 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6808 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6810 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6811 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6820 #ifndef DISABLE_REMOTING
6823 * mono_load_remote_field:
6824 * @this: pointer to an object
6825 * @klass: klass of the object containing @field
6826 * @field: the field to load
6827 * @res: a storage to store the result
6829 * This method is called by the runtime on attempts to load fields of
6830 * transparent proxy objects. @this points to such TP, @klass is the class of
6831 * the object containing @field. @res is a storage location which can be
6832 * used to store the result.
6834 * Returns: an address pointing to the value of field.
6837 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6839 MONO_REQ_GC_UNSAFE_MODE;
6841 static MonoMethod *getter = NULL;
6842 MonoDomain *domain = mono_domain_get ();
6843 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6844 MonoClass *field_class;
6845 MonoMethodMessage *msg;
6846 MonoArray *out_args;
6850 g_assert (mono_object_is_transparent_proxy (this_obj));
6851 g_assert (res != NULL);
6853 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6854 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6859 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6861 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6864 field_class = mono_class_from_mono_type (field->type);
6866 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6867 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6868 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6870 full_name = mono_type_get_full_name (klass);
6871 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6872 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6875 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6877 if (exc) mono_raise_exception ((MonoException *)exc);
6879 if (mono_array_length (out_args) == 0)
6882 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6884 if (field_class->valuetype) {
6885 return ((char *)*res) + sizeof (MonoObject);
6891 * mono_load_remote_field_new:
6896 * Missing documentation.
6899 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6901 MONO_REQ_GC_UNSAFE_MODE;
6903 static MonoMethod *getter = NULL;
6904 MonoDomain *domain = mono_domain_get ();
6905 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6906 MonoClass *field_class;
6907 MonoMethodMessage *msg;
6908 MonoArray *out_args;
6909 MonoObject *exc, *res;
6912 g_assert (mono_object_is_transparent_proxy (this_obj));
6914 field_class = mono_class_from_mono_type (field->type);
6916 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6918 if (field_class->valuetype) {
6919 res = mono_object_new (domain, field_class);
6920 val = ((gchar *) res) + sizeof (MonoObject);
6924 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6929 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6931 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6934 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6935 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6937 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6939 full_name = mono_type_get_full_name (klass);
6940 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6941 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6944 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6946 if (exc) mono_raise_exception ((MonoException *)exc);
6948 if (mono_array_length (out_args) == 0)
6951 res = mono_array_get (out_args, MonoObject *, 0);
6957 * mono_store_remote_field:
6958 * @this_obj: pointer to an object
6959 * @klass: klass of the object containing @field
6960 * @field: the field to load
6961 * @val: the value/object to store
6963 * This method is called by the runtime on attempts to store fields of
6964 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6965 * the object containing @field. @val is the new value to store in @field.
6968 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6970 MONO_REQ_GC_UNSAFE_MODE;
6972 static MonoMethod *setter = NULL;
6973 MonoDomain *domain = mono_domain_get ();
6974 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6975 MonoClass *field_class;
6976 MonoMethodMessage *msg;
6977 MonoArray *out_args;
6982 g_assert (mono_object_is_transparent_proxy (this_obj));
6984 field_class = mono_class_from_mono_type (field->type);
6986 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6987 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6988 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6993 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6995 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6998 if (field_class->valuetype)
6999 arg = mono_value_box (domain, field_class, val);
7001 arg = *((MonoObject **)val);
7004 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7005 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7007 full_name = mono_type_get_full_name (klass);
7008 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7009 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7010 mono_array_setref (msg->args, 2, arg);
7013 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7015 if (exc) mono_raise_exception ((MonoException *)exc);
7019 * mono_store_remote_field_new:
7025 * Missing documentation
7028 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7030 MONO_REQ_GC_UNSAFE_MODE;
7032 static MonoMethod *setter = NULL;
7033 MonoDomain *domain = mono_domain_get ();
7034 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7035 MonoClass *field_class;
7036 MonoMethodMessage *msg;
7037 MonoArray *out_args;
7041 g_assert (mono_object_is_transparent_proxy (this_obj));
7043 field_class = mono_class_from_mono_type (field->type);
7045 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7046 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7047 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7052 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7054 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7057 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7058 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7060 full_name = mono_type_get_full_name (klass);
7061 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7062 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7063 mono_array_setref (msg->args, 2, arg);
7066 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7068 if (exc) mono_raise_exception ((MonoException *)exc);
7073 * mono_create_ftnptr:
7075 * Given a function address, create a function descriptor for it.
7076 * This is only needed on some platforms.
7079 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7081 return callbacks.create_ftnptr (domain, addr);
7085 * mono_get_addr_from_ftnptr:
7087 * Given a pointer to a function descriptor, return the function address.
7088 * This is only needed on some platforms.
7091 mono_get_addr_from_ftnptr (gpointer descr)
7093 return callbacks.get_addr_from_ftnptr (descr);
7097 * mono_string_chars:
7100 * Returns a pointer to the UCS16 characters stored in the MonoString
7103 mono_string_chars (MonoString *s)
7105 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7111 * mono_string_length:
7114 * Returns the lenght in characters of the string
7117 mono_string_length (MonoString *s)
7119 MONO_REQ_GC_UNSAFE_MODE;
7125 * mono_array_length:
7126 * @array: a MonoArray*
7128 * Returns the total number of elements in the array. This works for
7129 * both vectors and multidimensional arrays.
7132 mono_array_length (MonoArray *array)
7134 MONO_REQ_GC_UNSAFE_MODE;
7136 return array->max_length;
7140 * mono_array_addr_with_size:
7141 * @array: a MonoArray*
7142 * @size: size of the array elements
7143 * @idx: index into the array
7145 * Returns the address of the @idx element in the array.
7148 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7150 MONO_REQ_GC_UNSAFE_MODE;
7152 return ((char*)(array)->vector) + size * idx;
7157 mono_glist_to_array (GList *list, MonoClass *eclass)
7159 MonoDomain *domain = mono_domain_get ();
7166 len = g_list_length (list);
7167 res = mono_array_new (domain, eclass, len);
7169 for (i = 0; list; list = list->next, i++)
7170 mono_array_set (res, gpointer, i, list->data);