2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internals.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-error-internals.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/checked-build.h>
46 #include <mono/utils/mono-threads.h>
47 #include "cominterop.h"
50 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
53 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
56 free_main_args (void);
59 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
62 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
63 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
64 static mono_mutex_t ldstr_section;
67 mono_runtime_object_init (MonoObject *this_obj)
69 MONO_REQ_GC_UNSAFE_MODE;
71 MonoMethod *method = NULL;
72 MonoClass *klass = this_obj->vtable->klass;
74 method = mono_class_get_method_from_name (klass, ".ctor", 0);
76 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
78 if (method->klass->valuetype)
79 this_obj = (MonoObject *)mono_object_unbox (this_obj);
80 mono_runtime_invoke (method, this_obj, NULL, NULL);
83 /* The pseudo algorithm for type initialization from the spec
84 Note it doesn't say anything about domains - only threads.
86 2. If the type is initialized you are done.
87 2.1. If the type is not yet initialized, try to take an
89 2.2. If successful, record this thread as responsible for
90 initializing the type and proceed to step 2.3.
91 2.2.1. If not, see whether this thread or any thread
92 waiting for this thread to complete already holds the lock.
93 2.2.2. If so, return since blocking would create a deadlock. This thread
94 will now see an incompletely initialized state for the type,
95 but no deadlock will arise.
96 2.2.3 If not, block until the type is initialized then return.
97 2.3 Initialize the parent type and then all interfaces implemented
99 2.4 Execute the type initialization code for this type.
100 2.5 Mark the type as initialized, release the initialization lock,
101 awaken any threads waiting for this type to be initialized,
108 MonoNativeThreadId initializing_tid;
109 guint32 waiting_count;
111 MonoCoopMutex initialization_section;
112 } TypeInitializationLock;
114 /* for locking access to type_initialization_hash and blocked_thread_hash */
115 static MonoCoopMutex type_initialization_section;
118 mono_type_initialization_lock (void)
120 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
121 mono_coop_mutex_lock (&type_initialization_section);
125 mono_type_initialization_unlock (void)
127 mono_coop_mutex_unlock (&type_initialization_section);
131 mono_type_init_lock (TypeInitializationLock *lock)
133 MONO_REQ_GC_NEUTRAL_MODE;
135 mono_coop_mutex_lock (&lock->initialization_section);
139 mono_type_init_unlock (TypeInitializationLock *lock)
141 mono_coop_mutex_unlock (&lock->initialization_section);
144 /* from vtable to lock */
145 static GHashTable *type_initialization_hash;
147 /* from thread id to thread id being waited on */
148 static GHashTable *blocked_thread_hash;
151 static MonoThread *main_thread;
153 /* Functions supplied by the runtime */
154 static MonoRuntimeCallbacks callbacks;
157 * mono_thread_set_main:
158 * @thread: thread to set as the main thread
160 * This function can be used to instruct the runtime to treat @thread
161 * as the main thread, ie, the thread that would normally execute the Main()
162 * method. This basically means that at the end of @thread, the runtime will
163 * wait for the existing foreground threads to quit and other such details.
166 mono_thread_set_main (MonoThread *thread)
168 MONO_REQ_GC_UNSAFE_MODE;
170 static gboolean registered = FALSE;
173 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
177 main_thread = thread;
181 mono_thread_get_main (void)
183 MONO_REQ_GC_UNSAFE_MODE;
189 mono_type_initialization_init (void)
191 mono_coop_mutex_init_recursive (&type_initialization_section);
192 type_initialization_hash = g_hash_table_new (NULL, NULL);
193 blocked_thread_hash = g_hash_table_new (NULL, NULL);
194 mono_os_mutex_init_recursive (&ldstr_section);
198 mono_type_initialization_cleanup (void)
201 /* This is causing race conditions with
202 * mono_release_type_locks
204 mono_coop_mutex_destroy (&type_initialization_section);
205 g_hash_table_destroy (type_initialization_hash);
206 type_initialization_hash = NULL;
208 mono_os_mutex_destroy (&ldstr_section);
209 g_hash_table_destroy (blocked_thread_hash);
210 blocked_thread_hash = NULL;
216 * get_type_init_exception_for_vtable:
218 * Return the stored type initialization exception for VTABLE.
220 static MonoException*
221 get_type_init_exception_for_vtable (MonoVTable *vtable)
223 MONO_REQ_GC_UNSAFE_MODE;
225 MonoDomain *domain = vtable->domain;
226 MonoClass *klass = vtable->klass;
230 if (!vtable->init_failed)
231 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
234 * If the initializing thread was rudely aborted, the exception is not stored
238 mono_domain_lock (domain);
239 if (domain->type_init_exception_hash)
240 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
241 mono_domain_unlock (domain);
244 if (klass->name_space && *klass->name_space)
245 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
247 full_name = g_strdup (klass->name);
248 ex = mono_get_exception_type_initialization (full_name, NULL);
255 * mono_runtime_class_init:
256 * @vtable: vtable that needs to be initialized
258 * This routine calls the class constructor for @vtable.
261 mono_runtime_class_init (MonoVTable *vtable)
263 MONO_REQ_GC_UNSAFE_MODE;
265 mono_runtime_class_init_full (vtable, TRUE);
269 * mono_runtime_class_init_full:
270 * @vtable that neeeds to be initialized
271 * @raise_exception is TRUE, exceptions are raised intead of returned
275 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
277 MONO_REQ_GC_UNSAFE_MODE;
280 MonoException *exc_to_throw;
281 MonoMethod *method = NULL;
284 MonoDomain *domain = vtable->domain;
285 TypeInitializationLock *lock;
286 MonoNativeThreadId tid;
287 int do_initialization = 0;
288 MonoDomain *last_domain = NULL;
290 if (vtable->initialized)
294 klass = vtable->klass;
296 if (!klass->image->checked_module_cctor) {
297 mono_image_check_for_module_cctor (klass->image);
298 if (klass->image->has_module_cctor) {
300 MonoClass *module_klass;
301 MonoVTable *module_vtable;
303 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
305 exc = mono_error_convert_to_exception (&error);
307 mono_raise_exception (exc);
311 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
314 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
319 method = mono_class_get_cctor (klass);
321 vtable->initialized = 1;
325 tid = mono_native_thread_id_get ();
327 mono_type_initialization_lock ();
328 /* double check... */
329 if (vtable->initialized) {
330 mono_type_initialization_unlock ();
333 if (vtable->init_failed) {
334 mono_type_initialization_unlock ();
336 /* The type initialization already failed once, rethrow the same exception */
338 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
339 return get_type_init_exception_for_vtable (vtable);
341 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
343 /* This thread will get to do the initialization */
344 if (mono_domain_get () != domain) {
345 /* Transfer into the target domain */
346 last_domain = mono_domain_get ();
347 if (!mono_domain_set (domain, FALSE)) {
348 vtable->initialized = 1;
349 mono_type_initialization_unlock ();
351 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
352 return mono_get_exception_appdomain_unloaded ();
355 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
356 mono_coop_mutex_init_recursive (&lock->initialization_section);
357 lock->initializing_tid = tid;
358 lock->waiting_count = 1;
360 /* grab the vtable lock while this thread still owns type_initialization_section */
361 /* This is why type_initialization_lock needs to enter blocking mode */
362 mono_type_init_lock (lock);
363 g_hash_table_insert (type_initialization_hash, vtable, lock);
364 do_initialization = 1;
367 TypeInitializationLock *pending_lock;
369 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
370 mono_type_initialization_unlock ();
373 /* see if the thread doing the initialization is already blocked on this thread */
374 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
375 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
376 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
377 if (!pending_lock->done) {
378 mono_type_initialization_unlock ();
381 /* the thread doing the initialization is blocked on this thread,
382 but on a lock that has already been freed. It just hasn't got
387 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
389 ++lock->waiting_count;
390 /* record the fact that we are waiting on the initializing thread */
391 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
393 mono_type_initialization_unlock ();
395 if (do_initialization) {
396 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
398 /* If the initialization failed, mark the class as unusable. */
399 /* Avoid infinite loops */
401 (klass->image == mono_defaults.corlib &&
402 !strcmp (klass->name_space, "System") &&
403 !strcmp (klass->name, "TypeInitializationException")))) {
404 vtable->init_failed = 1;
406 if (klass->name_space && *klass->name_space)
407 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
409 full_name = g_strdup (klass->name);
410 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
414 * Store the exception object so it could be thrown on subsequent
417 mono_domain_lock (domain);
418 if (!domain->type_init_exception_hash)
419 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
420 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
421 mono_domain_unlock (domain);
425 mono_domain_set (last_domain, TRUE);
427 mono_type_init_unlock (lock);
429 /* this just blocks until the initializing thread is done */
430 mono_type_init_lock (lock);
431 mono_type_init_unlock (lock);
434 mono_type_initialization_lock ();
435 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
436 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
437 --lock->waiting_count;
438 if (lock->waiting_count == 0) {
439 mono_coop_mutex_destroy (&lock->initialization_section);
440 g_hash_table_remove (type_initialization_hash, vtable);
443 mono_memory_barrier ();
444 if (!vtable->init_failed)
445 vtable->initialized = 1;
446 mono_type_initialization_unlock ();
448 if (vtable->init_failed) {
449 /* Either we were the initializing thread or we waited for the initialization */
451 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
452 return get_type_init_exception_for_vtable (vtable);
458 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
460 MONO_REQ_GC_NEUTRAL_MODE;
462 MonoVTable *vtable = (MonoVTable*)key;
464 TypeInitializationLock *lock = (TypeInitializationLock*) value;
465 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
468 * Have to set this since it cannot be set by the normal code in
469 * mono_runtime_class_init (). In this case, the exception object is not stored,
470 * and get_type_init_exception_for_class () needs to be aware of this.
472 vtable->init_failed = 1;
473 mono_type_init_unlock (lock);
474 --lock->waiting_count;
475 if (lock->waiting_count == 0) {
476 mono_coop_mutex_destroy (&lock->initialization_section);
485 mono_release_type_locks (MonoInternalThread *thread)
487 MONO_REQ_GC_UNSAFE_MODE;
489 mono_type_initialization_lock ();
490 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
491 mono_type_initialization_unlock ();
495 default_trampoline (MonoMethod *method)
501 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
503 g_assert_not_reached ();
508 #ifndef DISABLE_REMOTING
511 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
513 g_error ("remoting not installed");
517 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
521 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
523 g_assert_not_reached ();
527 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
528 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
529 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
530 static MonoImtThunkBuilder imt_thunk_builder;
531 static gboolean always_build_imt_thunks;
533 #if (MONO_IMT_SIZE > 32)
534 #error "MONO_IMT_SIZE cannot be larger than 32"
538 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
540 memcpy (&callbacks, cbs, sizeof (*cbs));
543 MonoRuntimeCallbacks*
544 mono_get_runtime_callbacks (void)
550 mono_install_trampoline (MonoTrampoline func)
552 arch_create_jit_trampoline = func? func: default_trampoline;
556 mono_install_jump_trampoline (MonoJumpTrampoline func)
558 arch_create_jump_trampoline = func? func: default_jump_trampoline;
561 #ifndef DISABLE_REMOTING
563 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
565 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
570 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
572 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
576 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
577 imt_thunk_builder = func;
581 mono_set_always_build_imt_thunks (gboolean value)
583 always_build_imt_thunks = value;
586 static MonoCompileFunc default_mono_compile_method = NULL;
589 * mono_install_compile_method:
590 * @func: function to install
592 * This is a VM internal routine
595 mono_install_compile_method (MonoCompileFunc func)
597 default_mono_compile_method = func;
601 * mono_compile_method:
602 * @method: The method to compile.
604 * This JIT-compiles the method, and returns the pointer to the native code
608 mono_compile_method (MonoMethod *method)
610 MONO_REQ_GC_NEUTRAL_MODE
612 if (!default_mono_compile_method) {
613 g_error ("compile method called on uninitialized runtime");
616 return default_mono_compile_method (method);
620 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
622 MONO_REQ_GC_NEUTRAL_MODE
624 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
628 mono_runtime_create_delegate_trampoline (MonoClass *klass)
630 MONO_REQ_GC_NEUTRAL_MODE
632 return arch_create_delegate_trampoline (mono_domain_get (), klass);
635 static MonoFreeMethodFunc default_mono_free_method = NULL;
638 * mono_install_free_method:
639 * @func: pointer to the MonoFreeMethodFunc used to release a method
641 * This is an internal VM routine, it is used for the engines to
642 * register a handler to release the resources associated with a method.
644 * Methods are freed when no more references to the delegate that holds
648 mono_install_free_method (MonoFreeMethodFunc func)
650 default_mono_free_method = func;
654 * mono_runtime_free_method:
655 * @domain; domain where the method is hosted
656 * @method: method to release
658 * This routine is invoked to free the resources associated with
659 * a method that has been JIT compiled. This is used to discard
660 * methods that were used only temporarily (for example, used in marshalling)
664 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
666 MONO_REQ_GC_NEUTRAL_MODE
668 if (default_mono_free_method != NULL)
669 default_mono_free_method (domain, method);
671 mono_method_clear_object (domain, method);
673 mono_free_method (method);
677 * The vtables in the root appdomain are assumed to be reachable by other
678 * roots, and we don't use typed allocation in the other domains.
681 /* The sync block is no longer a GC pointer */
682 #define GC_HEADER_BITMAP (0)
684 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
687 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
689 MONO_REQ_GC_NEUTRAL_MODE;
691 MonoClassField *field;
697 max_size = mono_class_data_size (klass) / sizeof (gpointer);
699 max_size = klass->instance_size / sizeof (gpointer);
700 if (max_size > size) {
701 g_assert (offset <= 0);
702 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
707 /*An Ephemeron cannot be marked by sgen*/
708 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
710 memset (bitmap, 0, size / 8);
715 for (p = klass; p != NULL; p = p->parent) {
716 gpointer iter = NULL;
717 while ((field = mono_class_get_fields (p, &iter))) {
721 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
723 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
726 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
729 /* FIXME: should not happen, flag as type load error */
730 if (field->type->byref)
733 if (static_fields && field->offset == -1)
737 pos = field->offset / sizeof (gpointer);
740 type = mono_type_get_underlying_type (field->type);
741 switch (type->type) {
744 case MONO_TYPE_FNPTR:
746 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
751 if (klass->image != mono_defaults.corlib)
754 case MONO_TYPE_STRING:
755 case MONO_TYPE_SZARRAY:
756 case MONO_TYPE_CLASS:
757 case MONO_TYPE_OBJECT:
758 case MONO_TYPE_ARRAY:
759 g_assert ((field->offset % sizeof(gpointer)) == 0);
761 g_assert (pos < size || pos <= max_size);
762 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
763 *max_set = MAX (*max_set, pos);
765 case MONO_TYPE_GENERICINST:
766 if (!mono_type_generic_inst_is_valuetype (type)) {
767 g_assert ((field->offset % sizeof(gpointer)) == 0);
769 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
770 *max_set = MAX (*max_set, pos);
775 case MONO_TYPE_VALUETYPE: {
776 MonoClass *fclass = mono_class_from_mono_type (field->type);
777 if (fclass->has_references) {
778 /* remove the object header */
779 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
793 case MONO_TYPE_BOOLEAN:
797 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
808 * mono_class_compute_bitmap:
810 * Mono internal function to compute a bitmap of reference fields in a class.
813 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
815 MONO_REQ_GC_NEUTRAL_MODE;
817 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
822 * similar to the above, but sets the bits in the bitmap for any non-ref field
823 * and ignores static fields
826 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
828 MonoClassField *field;
833 max_size = class->instance_size / sizeof (gpointer);
834 if (max_size >= size) {
835 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
838 for (p = class; p != NULL; p = p->parent) {
839 gpointer iter = NULL;
840 while ((field = mono_class_get_fields (p, &iter))) {
843 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
845 /* FIXME: should not happen, flag as type load error */
846 if (field->type->byref)
849 pos = field->offset / sizeof (gpointer);
852 type = mono_type_get_underlying_type (field->type);
853 switch (type->type) {
854 #if SIZEOF_VOID_P == 8
858 case MONO_TYPE_FNPTR:
863 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
864 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
865 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
868 #if SIZEOF_VOID_P == 4
872 case MONO_TYPE_FNPTR:
877 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
878 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
879 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
885 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
886 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
887 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
890 case MONO_TYPE_BOOLEAN:
893 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
895 case MONO_TYPE_STRING:
896 case MONO_TYPE_SZARRAY:
897 case MONO_TYPE_CLASS:
898 case MONO_TYPE_OBJECT:
899 case MONO_TYPE_ARRAY:
901 case MONO_TYPE_GENERICINST:
902 if (!mono_type_generic_inst_is_valuetype (type)) {
907 case MONO_TYPE_VALUETYPE: {
908 MonoClass *fclass = mono_class_from_mono_type (field->type);
909 /* remove the object header */
910 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
914 g_assert_not_reached ();
923 * mono_class_insecure_overlapping:
924 * check if a class with explicit layout has references and non-references
925 * fields overlapping.
927 * Returns: TRUE if it is insecure to load the type.
930 mono_class_insecure_overlapping (MonoClass *klass)
934 gsize default_bitmap [4] = {0};
936 gsize default_nrbitmap [4] = {0};
937 int i, insecure = FALSE;
940 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
941 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
943 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
944 int idx = i % (sizeof (bitmap [0]) * 8);
945 if (bitmap [idx] & nrbitmap [idx]) {
950 if (bitmap != default_bitmap)
952 if (nrbitmap != default_nrbitmap)
955 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
963 mono_string_alloc (int length)
965 MONO_REQ_GC_UNSAFE_MODE;
966 return mono_string_new_size (mono_domain_get (), length);
970 mono_class_compute_gc_descriptor (MonoClass *klass)
972 MONO_REQ_GC_NEUTRAL_MODE;
976 gsize default_bitmap [4] = {0};
977 static gboolean gcj_inited = FALSE;
982 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
983 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
986 mono_loader_unlock ();
990 mono_class_init (klass);
992 if (klass->gc_descr_inited)
995 klass->gc_descr_inited = TRUE;
996 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
998 bitmap = default_bitmap;
999 if (klass == mono_defaults.string_class) {
1000 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1001 } else if (klass->rank) {
1002 mono_class_compute_gc_descriptor (klass->element_class);
1003 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1005 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1006 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1007 class->name_space, class->name);*/
1009 /* remove the object header */
1010 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1011 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1012 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1013 class->name_space, class->name);*/
1014 if (bitmap != default_bitmap)
1018 /*static int count = 0;
1021 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1022 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1024 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1025 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1027 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1028 if (bitmap != default_bitmap)
1034 * field_is_special_static:
1035 * @fklass: The MonoClass to look up.
1036 * @field: The MonoClassField describing the field.
1038 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1039 * SPECIAL_STATIC_NONE otherwise.
1042 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1044 MONO_REQ_GC_NEUTRAL_MODE;
1046 MonoCustomAttrInfo *ainfo;
1048 ainfo = mono_custom_attrs_from_field (fklass, field);
1051 for (i = 0; i < ainfo->num_attrs; ++i) {
1052 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1053 if (klass->image == mono_defaults.corlib) {
1054 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1055 mono_custom_attrs_free (ainfo);
1056 return SPECIAL_STATIC_THREAD;
1058 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1059 mono_custom_attrs_free (ainfo);
1060 return SPECIAL_STATIC_CONTEXT;
1064 mono_custom_attrs_free (ainfo);
1065 return SPECIAL_STATIC_NONE;
1068 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1069 #define mix(a,b,c) { \
1070 a -= c; a ^= rot(c, 4); c += b; \
1071 b -= a; b ^= rot(a, 6); a += c; \
1072 c -= b; c ^= rot(b, 8); b += a; \
1073 a -= c; a ^= rot(c,16); c += b; \
1074 b -= a; b ^= rot(a,19); a += c; \
1075 c -= b; c ^= rot(b, 4); b += a; \
1077 #define final(a,b,c) { \
1078 c ^= b; c -= rot(b,14); \
1079 a ^= c; a -= rot(c,11); \
1080 b ^= a; b -= rot(a,25); \
1081 c ^= b; c -= rot(b,16); \
1082 a ^= c; a -= rot(c,4); \
1083 b ^= a; b -= rot(a,14); \
1084 c ^= b; c -= rot(b,24); \
1088 * mono_method_get_imt_slot:
1090 * The IMT slot is embedded into AOTed code, so this must return the same value
1091 * for the same method across all executions. This means:
1092 * - pointers shouldn't be used as hash values.
1093 * - mono_metadata_str_hash () should be used for hashing strings.
1096 mono_method_get_imt_slot (MonoMethod *method)
1098 MONO_REQ_GC_NEUTRAL_MODE;
1100 MonoMethodSignature *sig;
1102 guint32 *hashes_start, *hashes;
1106 /* This can be used to stress tests the collision code */
1110 * We do this to simplify generic sharing. It will hurt
1111 * performance in cases where a class implements two different
1112 * instantiations of the same generic interface.
1113 * The code in build_imt_slots () depends on this.
1115 if (method->is_inflated)
1116 method = ((MonoMethodInflated*)method)->declaring;
1118 sig = mono_method_signature (method);
1119 hashes_count = sig->param_count + 4;
1120 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1121 hashes = hashes_start;
1123 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1124 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1125 method->klass->name_space, method->klass->name, method->name);
1128 /* Initialize hashes */
1129 hashes [0] = mono_metadata_str_hash (method->klass->name);
1130 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1131 hashes [2] = mono_metadata_str_hash (method->name);
1132 hashes [3] = mono_metadata_type_hash (sig->ret);
1133 for (i = 0; i < sig->param_count; i++) {
1134 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1137 /* Setup internal state */
1138 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1140 /* Handle most of the hashes */
1141 while (hashes_count > 3) {
1150 /* Handle the last 3 hashes (all the case statements fall through) */
1151 switch (hashes_count) {
1152 case 3 : c += hashes [2];
1153 case 2 : b += hashes [1];
1154 case 1 : a += hashes [0];
1156 case 0: /* nothing left to add */
1160 free (hashes_start);
1161 /* Report the result */
1162 return c % MONO_IMT_SIZE;
1171 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1172 MONO_REQ_GC_NEUTRAL_MODE;
1174 guint32 imt_slot = mono_method_get_imt_slot (method);
1175 MonoImtBuilderEntry *entry;
1177 if (slot_num >= 0 && imt_slot != slot_num) {
1178 /* we build just a single imt slot and this is not it */
1182 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1183 entry->key = method;
1184 entry->value.vtable_slot = vtable_slot;
1185 entry->next = imt_builder [imt_slot];
1186 if (imt_builder [imt_slot] != NULL) {
1187 entry->children = imt_builder [imt_slot]->children + 1;
1188 if (entry->children == 1) {
1189 mono_stats.imt_slots_with_collisions++;
1190 *imt_collisions_bitmap |= (1 << imt_slot);
1193 entry->children = 0;
1194 mono_stats.imt_used_slots++;
1196 imt_builder [imt_slot] = entry;
1199 char *method_name = mono_method_full_name (method, TRUE);
1200 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1201 method, method_name, imt_slot, vtable_slot, entry->children);
1202 g_free (method_name);
1209 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1211 MonoMethod *method = e->key;
1212 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1216 method->klass->name_space,
1217 method->klass->name,
1220 printf (" * %s: NULL\n", message);
1226 compare_imt_builder_entries (const void *p1, const void *p2) {
1227 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1228 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1230 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1234 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1236 MONO_REQ_GC_NEUTRAL_MODE;
1238 int count = end - start;
1239 int chunk_start = out_array->len;
1242 for (i = start; i < end; ++i) {
1243 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1244 item->key = sorted_array [i]->key;
1245 item->value = sorted_array [i]->value;
1246 item->has_target_code = sorted_array [i]->has_target_code;
1247 item->is_equals = TRUE;
1249 item->check_target_idx = out_array->len + 1;
1251 item->check_target_idx = 0;
1252 g_ptr_array_add (out_array, item);
1255 int middle = start + count / 2;
1256 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1258 item->key = sorted_array [middle]->key;
1259 item->is_equals = FALSE;
1260 g_ptr_array_add (out_array, item);
1261 imt_emit_ir (sorted_array, start, middle, out_array);
1262 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1268 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1269 MONO_REQ_GC_NEUTRAL_MODE;
1271 int number_of_entries = entries->children + 1;
1272 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1273 GPtrArray *result = g_ptr_array_new ();
1274 MonoImtBuilderEntry *current_entry;
1277 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1278 sorted_array [i] = current_entry;
1280 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1282 /*for (i = 0; i < number_of_entries; i++) {
1283 print_imt_entry (" sorted array:", sorted_array [i], i);
1286 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1288 free (sorted_array);
1293 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1295 MONO_REQ_GC_NEUTRAL_MODE;
1297 if (imt_builder_entry != NULL) {
1298 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1299 /* No collision, return the vtable slot contents */
1300 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1302 /* Collision, build the thunk */
1303 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1306 result = imt_thunk_builder (vtable, domain,
1307 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1308 for (i = 0; i < imt_ir->len; ++i)
1309 g_free (g_ptr_array_index (imt_ir, i));
1310 g_ptr_array_free (imt_ir, TRUE);
1322 static MonoImtBuilderEntry*
1323 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1326 * LOCKING: requires the loader and domain locks.
1330 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1332 MONO_REQ_GC_NEUTRAL_MODE;
1336 guint32 imt_collisions_bitmap = 0;
1337 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1338 int method_count = 0;
1339 gboolean record_method_count_for_max_collisions = FALSE;
1340 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1343 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1345 for (i = 0; i < klass->interface_offsets_count; ++i) {
1346 MonoClass *iface = klass->interfaces_packed [i];
1347 int interface_offset = klass->interface_offsets_packed [i];
1348 int method_slot_in_interface, vt_slot;
1350 if (mono_class_has_variant_generic_params (iface))
1351 has_variant_iface = TRUE;
1353 mono_class_setup_methods (iface);
1354 vt_slot = interface_offset;
1355 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1358 if (slot_num >= 0 && iface->is_inflated) {
1360 * The imt slot of the method is the same as for its declaring method,
1361 * see the comment in mono_method_get_imt_slot (), so we can
1362 * avoid inflating methods which will be discarded by
1363 * add_imt_builder_entry anyway.
1365 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1366 if (mono_method_get_imt_slot (method) != slot_num) {
1371 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1372 if (method->is_generic) {
1373 has_generic_virtual = TRUE;
1378 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1379 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1384 if (extra_interfaces) {
1385 int interface_offset = klass->vtable_size;
1387 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1388 MonoClass* iface = (MonoClass *)list_item->data;
1389 int method_slot_in_interface;
1390 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1391 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1393 if (method->is_generic)
1394 has_generic_virtual = TRUE;
1395 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1397 interface_offset += iface->method.count;
1400 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1401 /* overwrite the imt slot only if we're building all the entries or if
1402 * we're building this specific one
1404 if (slot_num < 0 || i == slot_num) {
1405 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1408 if (imt_builder [i]) {
1409 MonoImtBuilderEntry *entry;
1411 /* Link entries with imt_builder [i] */
1412 for (entry = entries; entry->next; entry = entry->next) {
1414 MonoMethod *method = (MonoMethod*)entry->key;
1415 char *method_name = mono_method_full_name (method, TRUE);
1416 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1417 g_free (method_name);
1420 entry->next = imt_builder [i];
1421 entries->children += imt_builder [i]->children + 1;
1423 imt_builder [i] = entries;
1426 if (has_generic_virtual || has_variant_iface) {
1428 * There might be collisions later when the the thunk is expanded.
1430 imt_collisions_bitmap |= (1 << i);
1433 * The IMT thunk might be called with an instance of one of the
1434 * generic virtual methods, so has to fallback to the IMT trampoline.
1436 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1438 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1441 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1445 if (imt_builder [i] != NULL) {
1446 int methods_in_slot = imt_builder [i]->children + 1;
1447 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1448 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1449 record_method_count_for_max_collisions = TRUE;
1451 method_count += methods_in_slot;
1455 mono_stats.imt_number_of_methods += method_count;
1456 if (record_method_count_for_max_collisions) {
1457 mono_stats.imt_method_count_when_max_collisions = method_count;
1460 for (i = 0; i < MONO_IMT_SIZE; i++) {
1461 MonoImtBuilderEntry* entry = imt_builder [i];
1462 while (entry != NULL) {
1463 MonoImtBuilderEntry* next = entry->next;
1469 /* we OR the bitmap since we may build just a single imt slot at a time */
1470 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1474 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1475 MONO_REQ_GC_NEUTRAL_MODE;
1477 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1481 * mono_vtable_build_imt_slot:
1482 * @vtable: virtual object table struct
1483 * @imt_slot: slot in the IMT table
1485 * Fill the given @imt_slot in the IMT table of @vtable with
1486 * a trampoline or a thunk for the case of collisions.
1487 * This is part of the internal mono API.
1489 * LOCKING: Take the domain lock.
1492 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1494 MONO_REQ_GC_NEUTRAL_MODE;
1496 gpointer *imt = (gpointer*)vtable;
1497 imt -= MONO_IMT_SIZE;
1498 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1500 /* no support for extra interfaces: the proxy objects will need
1501 * to build the complete IMT
1502 * Update and heck needs to ahppen inside the proper domain lock, as all
1503 * the changes made to a MonoVTable.
1505 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1506 mono_domain_lock (vtable->domain);
1507 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1508 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1509 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1510 mono_domain_unlock (vtable->domain);
1511 mono_loader_unlock ();
1516 * The first two free list entries both belong to the wait list: The
1517 * first entry is the pointer to the head of the list and the second
1518 * entry points to the last element. That way appending and removing
1519 * the first element are both O(1) operations.
1521 #ifdef MONO_SMALL_CONFIG
1522 #define NUM_FREE_LISTS 6
1524 #define NUM_FREE_LISTS 12
1526 #define FIRST_FREE_LIST_SIZE 64
1527 #define MAX_WAIT_LENGTH 50
1528 #define THUNK_THRESHOLD 10
1531 * LOCKING: The domain lock must be held.
1534 init_thunk_free_lists (MonoDomain *domain)
1536 MONO_REQ_GC_NEUTRAL_MODE;
1538 if (domain->thunk_free_lists)
1540 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1544 list_index_for_size (int item_size)
1547 int size = FIRST_FREE_LIST_SIZE;
1549 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1558 * mono_method_alloc_generic_virtual_thunk:
1560 * @size: size in bytes
1562 * Allocs size bytes to be used for the code of a generic virtual
1563 * thunk. It's either allocated from the domain's code manager or
1564 * reused from a previously invalidated piece.
1566 * LOCKING: The domain lock must be held.
1569 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1571 MONO_REQ_GC_NEUTRAL_MODE;
1573 static gboolean inited = FALSE;
1574 static int generic_virtual_thunks_size = 0;
1578 MonoThunkFreeList **l;
1580 init_thunk_free_lists (domain);
1582 size += sizeof (guint32);
1583 if (size < sizeof (MonoThunkFreeList))
1584 size = sizeof (MonoThunkFreeList);
1586 i = list_index_for_size (size);
1587 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1588 if ((*l)->size >= size) {
1589 MonoThunkFreeList *item = *l;
1591 return ((guint32*)item) + 1;
1595 /* no suitable item found - search lists of larger sizes */
1596 while (++i < NUM_FREE_LISTS) {
1597 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1600 g_assert (item->size > size);
1601 domain->thunk_free_lists [i] = item->next;
1602 return ((guint32*)item) + 1;
1605 /* still nothing found - allocate it */
1607 mono_counters_register ("Generic virtual thunk bytes",
1608 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1611 generic_virtual_thunks_size += size;
1613 p = (guint32 *)mono_domain_code_reserve (domain, size);
1616 mono_domain_lock (domain);
1617 if (!domain->generic_virtual_thunks)
1618 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1619 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1620 mono_domain_unlock (domain);
1626 * LOCKING: The domain lock must be held.
1629 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1631 MONO_REQ_GC_NEUTRAL_MODE;
1633 guint32 *p = (guint32 *)code;
1634 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1635 gboolean found = FALSE;
1637 mono_domain_lock (domain);
1638 if (!domain->generic_virtual_thunks)
1639 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1640 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1642 mono_domain_unlock (domain);
1645 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1647 init_thunk_free_lists (domain);
1649 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1650 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1651 int length = item->length;
1654 /* unlink the first item from the wait list */
1655 domain->thunk_free_lists [0] = item->next;
1656 domain->thunk_free_lists [0]->length = length - 1;
1658 i = list_index_for_size (item->size);
1660 /* put it in the free list */
1661 item->next = domain->thunk_free_lists [i];
1662 domain->thunk_free_lists [i] = item;
1666 if (domain->thunk_free_lists [1]) {
1667 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1668 domain->thunk_free_lists [0]->length++;
1670 g_assert (!domain->thunk_free_lists [0]);
1672 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1673 domain->thunk_free_lists [0]->length = 1;
1677 typedef struct _GenericVirtualCase {
1681 struct _GenericVirtualCase *next;
1682 } GenericVirtualCase;
1685 * get_generic_virtual_entries:
1687 * Return IMT entries for the generic virtual method instances and
1688 * variant interface methods for vtable slot
1691 static MonoImtBuilderEntry*
1692 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1694 MONO_REQ_GC_NEUTRAL_MODE;
1696 GenericVirtualCase *list;
1697 MonoImtBuilderEntry *entries;
1699 mono_domain_lock (domain);
1700 if (!domain->generic_virtual_cases)
1701 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1703 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1706 for (; list; list = list->next) {
1707 MonoImtBuilderEntry *entry;
1709 if (list->count < THUNK_THRESHOLD)
1712 entry = g_new0 (MonoImtBuilderEntry, 1);
1713 entry->key = list->method;
1714 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1715 entry->has_target_code = 1;
1717 entry->children = entries->children + 1;
1718 entry->next = entries;
1722 mono_domain_unlock (domain);
1724 /* FIXME: Leaking memory ? */
1729 * mono_method_add_generic_virtual_invocation:
1731 * @vtable_slot: pointer to the vtable slot
1732 * @method: the inflated generic virtual method
1733 * @code: the method's code
1735 * Registers a call via unmanaged code to a generic virtual method
1736 * instantiation or variant interface method. If the number of calls reaches a threshold
1737 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1738 * virtual method thunk.
1741 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1742 gpointer *vtable_slot,
1743 MonoMethod *method, gpointer code)
1745 MONO_REQ_GC_NEUTRAL_MODE;
1747 static gboolean inited = FALSE;
1748 static int num_added = 0;
1750 GenericVirtualCase *gvc, *list;
1751 MonoImtBuilderEntry *entries;
1755 mono_domain_lock (domain);
1756 if (!domain->generic_virtual_cases)
1757 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1759 /* Check whether the case was already added */
1760 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1763 if (gvc->method == method)
1768 /* If not found, make a new one */
1770 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1771 gvc->method = method;
1774 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1776 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1779 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1785 if (++gvc->count == THUNK_THRESHOLD) {
1786 gpointer *old_thunk = (void **)*vtable_slot;
1787 gpointer vtable_trampoline = NULL;
1788 gpointer imt_trampoline = NULL;
1790 if ((gpointer)vtable_slot < (gpointer)vtable) {
1791 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1792 int imt_slot = MONO_IMT_SIZE + displacement;
1794 /* Force the rebuild of the thunk at the next call */
1795 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1796 *vtable_slot = imt_trampoline;
1798 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1800 entries = get_generic_virtual_entries (domain, vtable_slot);
1802 sorted = imt_sort_slot_entries (entries);
1804 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1808 MonoImtBuilderEntry *next = entries->next;
1813 for (i = 0; i < sorted->len; ++i)
1814 g_free (g_ptr_array_index (sorted, i));
1815 g_ptr_array_free (sorted, TRUE);
1818 #ifndef __native_client__
1819 /* We don't re-use any thunks as there is a lot of overhead */
1820 /* to deleting and re-using code in Native Client. */
1821 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1822 invalidate_generic_virtual_thunk (domain, old_thunk);
1826 mono_domain_unlock (domain);
1829 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1832 * mono_class_vtable:
1833 * @domain: the application domain
1834 * @class: the class to initialize
1836 * VTables are domain specific because we create domain specific code, and
1837 * they contain the domain specific static class data.
1838 * On failure, NULL is returned, and class->exception_type is set.
1841 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1843 return mono_class_vtable_full (domain, klass, FALSE);
1847 * mono_class_vtable_full:
1848 * @domain: the application domain
1849 * @class: the class to initialize
1850 * @raise_on_error if an exception should be raised on failure or not
1852 * VTables are domain specific because we create domain specific code, and
1853 * they contain the domain specific static class data.
1856 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1858 MONO_REQ_GC_UNSAFE_MODE;
1860 MonoClassRuntimeInfo *runtime_info;
1864 if (klass->exception_type) {
1866 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1870 /* this check can be inlined in jitted code, too */
1871 runtime_info = klass->runtime_info;
1872 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1873 return runtime_info->domain_vtables [domain->domain_id];
1874 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1878 * mono_class_try_get_vtable:
1879 * @domain: the application domain
1880 * @class: the class to initialize
1882 * This function tries to get the associated vtable from @class if
1883 * it was already created.
1886 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1888 MONO_REQ_GC_NEUTRAL_MODE;
1890 MonoClassRuntimeInfo *runtime_info;
1894 runtime_info = klass->runtime_info;
1895 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1896 return runtime_info->domain_vtables [domain->domain_id];
1901 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1903 MONO_REQ_GC_NEUTRAL_MODE;
1905 size_t alloc_offset;
1908 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1909 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1910 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1912 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1913 g_assert ((imt_table_bytes & 7) == 4);
1920 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1924 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1926 MONO_REQ_GC_UNSAFE_MODE;
1929 MonoClassRuntimeInfo *runtime_info, *old_info;
1930 MonoClassField *field;
1932 int i, vtable_slots;
1933 size_t imt_table_bytes;
1935 guint32 vtable_size, class_size;
1937 gpointer *interface_offsets;
1939 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1940 mono_domain_lock (domain);
1941 runtime_info = klass->runtime_info;
1942 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1943 mono_domain_unlock (domain);
1944 mono_loader_unlock ();
1945 return runtime_info->domain_vtables [domain->domain_id];
1947 if (!klass->inited || klass->exception_type) {
1948 if (!mono_class_init (klass) || klass->exception_type) {
1949 mono_domain_unlock (domain);
1950 mono_loader_unlock ();
1952 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1957 /* Array types require that their element type be valid*/
1958 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1959 MonoClass *element_class = klass->element_class;
1960 if (!element_class->inited)
1961 mono_class_init (element_class);
1963 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1964 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1965 mono_class_setup_vtable (element_class);
1967 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1968 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1969 if (klass->exception_type == MONO_EXCEPTION_NONE)
1970 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1971 mono_domain_unlock (domain);
1972 mono_loader_unlock ();
1974 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1980 * For some classes, mono_class_init () already computed klass->vtable_size, and
1981 * that is all that is needed because of the vtable trampolines.
1983 if (!klass->vtable_size)
1984 mono_class_setup_vtable (klass);
1986 if (klass->generic_class && !klass->vtable)
1987 mono_class_check_vtable_constraints (klass, NULL);
1989 /* Initialize klass->has_finalize */
1990 mono_class_has_finalizer (klass);
1992 if (klass->exception_type) {
1993 mono_domain_unlock (domain);
1994 mono_loader_unlock ();
1996 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2000 vtable_slots = klass->vtable_size;
2001 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2002 class_size = mono_class_data_size (klass);
2006 if (klass->interface_offsets_count) {
2007 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2008 mono_stats.imt_number_of_tables++;
2009 mono_stats.imt_tables_size += imt_table_bytes;
2011 imt_table_bytes = 0;
2014 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2016 mono_stats.used_class_count++;
2017 mono_stats.class_vtable_size += vtable_size;
2019 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2020 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2021 g_assert (!((gsize)vt & 7));
2024 vt->rank = klass->rank;
2025 vt->domain = domain;
2027 mono_class_compute_gc_descriptor (klass);
2029 * We can't use typed allocation in the non-root domains, since the
2030 * collector needs the GC descriptor stored in the vtable even after
2031 * the mempool containing the vtable is destroyed when the domain is
2032 * unloaded. An alternative might be to allocate vtables in the GC
2033 * heap, but this does not seem to work (it leads to crashes inside
2034 * libgc). If that approach is tried, two gc descriptors need to be
2035 * allocated for each class: one for the root domain, and one for all
2036 * other domains. The second descriptor should contain a bit for the
2037 * vtable field in MonoObject, since we can no longer assume the
2038 * vtable is reachable by other roots after the appdomain is unloaded.
2040 #ifdef HAVE_BOEHM_GC
2041 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2042 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2045 vt->gc_descr = klass->gc_descr;
2047 gc_bits = mono_gc_get_vtable_bits (klass);
2048 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2050 vt->gc_bits = gc_bits;
2053 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2054 if (klass->has_static_refs) {
2055 MonoGCDescriptor statics_gc_descr;
2057 gsize default_bitmap [4] = {0};
2060 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2061 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2062 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2063 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2064 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2065 if (bitmap != default_bitmap)
2068 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2070 vt->has_static_fields = TRUE;
2071 mono_stats.class_static_data_size += class_size;
2075 while ((field = mono_class_get_fields (klass, &iter))) {
2076 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2078 if (mono_field_is_deleted (field))
2080 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2081 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2082 if (special_static != SPECIAL_STATIC_NONE) {
2083 guint32 size, offset;
2085 gsize default_bitmap [4] = {0};
2090 if (mono_type_is_reference (field->type)) {
2091 default_bitmap [0] = 1;
2093 bitmap = default_bitmap;
2094 } else if (mono_type_is_struct (field->type)) {
2095 fclass = mono_class_from_mono_type (field->type);
2096 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2097 numbits = max_set + 1;
2099 default_bitmap [0] = 0;
2101 bitmap = default_bitmap;
2103 size = mono_type_size (field->type, &align);
2104 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2105 if (!domain->special_static_fields)
2106 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2107 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2108 if (bitmap != default_bitmap)
2111 * This marks the field as special static to speed up the
2112 * checks in mono_field_static_get/set_value ().
2118 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2119 MonoClass *fklass = mono_class_from_mono_type (field->type);
2120 const char *data = mono_field_get_data (field);
2122 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2123 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2124 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2127 if (fklass->valuetype) {
2128 memcpy (t, data, mono_class_value_size (fklass, NULL));
2130 /* it's a pointer type: add check */
2131 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2138 vt->max_interface_id = klass->max_interface_id;
2139 vt->interface_bitmap = klass->interface_bitmap;
2141 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2142 // class->name, klass->interface_offsets_count);
2144 /* Initialize vtable */
2145 if (callbacks.get_vtable_trampoline) {
2146 // This also covers the AOT case
2147 for (i = 0; i < klass->vtable_size; ++i) {
2148 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2151 mono_class_setup_vtable (klass);
2153 for (i = 0; i < klass->vtable_size; ++i) {
2156 if ((cm = klass->vtable [i]))
2157 vt->vtable [i] = arch_create_jit_trampoline (cm);
2161 if (imt_table_bytes) {
2162 /* Now that the vtable is full, we can actually fill up the IMT */
2163 for (i = 0; i < MONO_IMT_SIZE; ++i)
2164 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2168 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2169 * re-acquire them and check if another thread has created the vtable in the meantime.
2171 /* Special case System.MonoType to avoid infinite recursion */
2172 if (klass != mono_defaults.monotype_class) {
2173 /*FIXME check for OOM*/
2174 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2175 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2176 /* This is unregistered in
2177 unregister_vtable_reflection_type() in
2179 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2182 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2184 /* class_vtable_array keeps an array of created vtables
2186 g_ptr_array_add (domain->class_vtable_array, vt);
2187 /* klass->runtime_info is protected by the loader lock, both when
2188 * it it enlarged and when it is stored info.
2192 * Store the vtable in klass->runtime_info.
2193 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2195 mono_memory_barrier ();
2197 old_info = klass->runtime_info;
2198 if (old_info && old_info->max_domain >= domain->domain_id) {
2199 /* someone already created a large enough runtime info */
2200 old_info->domain_vtables [domain->domain_id] = vt;
2202 int new_size = domain->domain_id;
2204 new_size = MAX (new_size, old_info->max_domain);
2206 /* make the new size a power of two */
2208 while (new_size > i)
2211 /* this is a bounded memory retention issue: may want to
2212 * handle it differently when we'll have a rcu-like system.
2214 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2215 runtime_info->max_domain = new_size - 1;
2216 /* copy the stuff from the older info */
2218 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2220 runtime_info->domain_vtables [domain->domain_id] = vt;
2222 mono_memory_barrier ();
2223 klass->runtime_info = runtime_info;
2226 if (klass == mono_defaults.monotype_class) {
2227 /*FIXME check for OOM*/
2228 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2229 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2230 /* This is unregistered in
2231 unregister_vtable_reflection_type() in
2233 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2236 mono_domain_unlock (domain);
2237 mono_loader_unlock ();
2239 /* make sure the parent is initialized */
2240 /*FIXME shouldn't this fail the current type?*/
2242 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2247 #ifndef DISABLE_REMOTING
2249 * mono_class_proxy_vtable:
2250 * @domain: the application domain
2251 * @remove_class: the remote class
2253 * Creates a vtable for transparent proxies. It is basically
2254 * a copy of the real vtable of the class wrapped in @remote_class,
2255 * but all function pointers invoke the remoting functions, and
2256 * vtable->klass points to the transparent proxy class, and not to @class.
2259 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2261 MONO_REQ_GC_UNSAFE_MODE;
2264 MonoVTable *vt, *pvt;
2265 int i, j, vtsize, extra_interface_vtsize = 0;
2266 guint32 max_interface_id;
2268 GSList *extra_interfaces = NULL;
2269 MonoClass *klass = remote_class->proxy_class;
2270 gpointer *interface_offsets;
2273 size_t imt_table_bytes;
2275 #ifdef COMPRESSED_INTERFACE_BITMAP
2279 vt = mono_class_vtable (domain, klass);
2280 g_assert (vt); /*FIXME property handle failure*/
2281 max_interface_id = vt->max_interface_id;
2283 /* Calculate vtable space for extra interfaces */
2284 for (j = 0; j < remote_class->interface_count; j++) {
2285 MonoClass* iclass = remote_class->interfaces[j];
2289 /*FIXME test for interfaces with variant generic arguments*/
2290 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2291 continue; /* interface implemented by the class */
2292 if (g_slist_find (extra_interfaces, iclass))
2295 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2297 method_count = mono_class_num_methods (iclass);
2299 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2300 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2302 for (i = 0; i < ifaces->len; ++i) {
2303 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2304 /*FIXME test for interfaces with variant generic arguments*/
2305 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2306 continue; /* interface implemented by the class */
2307 if (g_slist_find (extra_interfaces, ic))
2309 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2310 method_count += mono_class_num_methods (ic);
2312 g_ptr_array_free (ifaces, TRUE);
2315 extra_interface_vtsize += method_count * sizeof (gpointer);
2316 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2319 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2320 mono_stats.imt_number_of_tables++;
2321 mono_stats.imt_tables_size += imt_table_bytes;
2323 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2325 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2327 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2328 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2329 g_assert (!((gsize)pvt & 7));
2331 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2333 pvt->klass = mono_defaults.transparent_proxy_class;
2334 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2335 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2337 /* initialize vtable */
2338 mono_class_setup_vtable (klass);
2339 for (i = 0; i < klass->vtable_size; ++i) {
2342 if ((cm = klass->vtable [i]))
2343 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2345 pvt->vtable [i] = NULL;
2348 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2349 /* create trampolines for abstract methods */
2350 for (k = klass; k; k = k->parent) {
2352 gpointer iter = NULL;
2353 while ((m = mono_class_get_methods (k, &iter)))
2354 if (!pvt->vtable [m->slot])
2355 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2359 pvt->max_interface_id = max_interface_id;
2360 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2361 #ifdef COMPRESSED_INTERFACE_BITMAP
2362 bitmap = (uint8_t *)g_malloc0 (bsize);
2364 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2367 for (i = 0; i < klass->interface_offsets_count; ++i) {
2368 int interface_id = klass->interfaces_packed [i]->interface_id;
2369 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2372 if (extra_interfaces) {
2373 int slot = klass->vtable_size;
2379 /* Create trampolines for the methods of the interfaces */
2380 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2381 interf = (MonoClass *)list_item->data;
2383 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2387 while ((cm = mono_class_get_methods (interf, &iter)))
2388 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2390 slot += mono_class_num_methods (interf);
2394 /* Now that the vtable is full, we can actually fill up the IMT */
2395 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2396 if (extra_interfaces) {
2397 g_slist_free (extra_interfaces);
2400 #ifdef COMPRESSED_INTERFACE_BITMAP
2401 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2402 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2403 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2406 pvt->interface_bitmap = bitmap;
2411 #endif /* DISABLE_REMOTING */
2414 * mono_class_field_is_special_static:
2416 * Returns whether @field is a thread/context static field.
2419 mono_class_field_is_special_static (MonoClassField *field)
2421 MONO_REQ_GC_NEUTRAL_MODE
2423 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2425 if (mono_field_is_deleted (field))
2427 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2428 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2435 * mono_class_field_get_special_static_type:
2436 * @field: The MonoClassField describing the field.
2438 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2439 * SPECIAL_STATIC_NONE otherwise.
2442 mono_class_field_get_special_static_type (MonoClassField *field)
2444 MONO_REQ_GC_NEUTRAL_MODE
2446 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2447 return SPECIAL_STATIC_NONE;
2448 if (mono_field_is_deleted (field))
2449 return SPECIAL_STATIC_NONE;
2450 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2451 return field_is_special_static (field->parent, field);
2452 return SPECIAL_STATIC_NONE;
2456 * mono_class_has_special_static_fields:
2458 * Returns whenever @klass has any thread/context static fields.
2461 mono_class_has_special_static_fields (MonoClass *klass)
2463 MONO_REQ_GC_NEUTRAL_MODE
2465 MonoClassField *field;
2469 while ((field = mono_class_get_fields (klass, &iter))) {
2470 g_assert (field->parent == klass);
2471 if (mono_class_field_is_special_static (field))
2478 #ifndef DISABLE_REMOTING
2480 * create_remote_class_key:
2481 * Creates an array of pointers that can be used as a hash key for a remote class.
2482 * The first element of the array is the number of pointers.
2485 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2487 MONO_REQ_GC_NEUTRAL_MODE;
2492 if (remote_class == NULL) {
2493 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2494 key = (void **)g_malloc (sizeof(gpointer) * 3);
2495 key [0] = GINT_TO_POINTER (2);
2496 key [1] = mono_defaults.marshalbyrefobject_class;
2497 key [2] = extra_class;
2499 key = (void **)g_malloc (sizeof(gpointer) * 2);
2500 key [0] = GINT_TO_POINTER (1);
2501 key [1] = extra_class;
2504 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2505 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2506 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2507 key [1] = remote_class->proxy_class;
2509 // Keep the list of interfaces sorted
2510 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2511 if (extra_class && remote_class->interfaces [i] > extra_class) {
2512 key [j++] = extra_class;
2515 key [j] = remote_class->interfaces [i];
2518 key [j] = extra_class;
2520 // Replace the old class. The interface list is the same
2521 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2522 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2523 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2524 for (i = 0; i < remote_class->interface_count; i++)
2525 key [2 + i] = remote_class->interfaces [i];
2533 * copy_remote_class_key:
2535 * Make a copy of KEY in the domain and return the copy.
2538 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2540 MONO_REQ_GC_NEUTRAL_MODE
2542 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2543 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2545 memcpy (mp_key, key, key_size);
2551 * mono_remote_class:
2552 * @domain: the application domain
2553 * @class_name: name of the remote class
2555 * Creates and initializes a MonoRemoteClass object for a remote type.
2557 * Can raise an exception on failure.
2560 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2562 MONO_REQ_GC_UNSAFE_MODE;
2565 MonoRemoteClass *rc;
2566 gpointer* key, *mp_key;
2569 key = create_remote_class_key (NULL, proxy_class);
2571 mono_domain_lock (domain);
2572 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2576 mono_domain_unlock (domain);
2580 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2581 if (!mono_error_ok (&error)) {
2583 mono_domain_unlock (domain);
2584 mono_error_raise_exception (&error);
2587 mp_key = copy_remote_class_key (domain, key);
2591 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2592 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2593 rc->interface_count = 1;
2594 rc->interfaces [0] = proxy_class;
2595 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2597 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2598 rc->interface_count = 0;
2599 rc->proxy_class = proxy_class;
2602 rc->default_vtable = NULL;
2603 rc->xdomain_vtable = NULL;
2604 rc->proxy_class_name = name;
2605 #ifndef DISABLE_PERFCOUNTERS
2606 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2609 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2611 mono_domain_unlock (domain);
2616 * clone_remote_class:
2617 * Creates a copy of the remote_class, adding the provided class or interface
2619 static MonoRemoteClass*
2620 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2622 MONO_REQ_GC_NEUTRAL_MODE;
2624 MonoRemoteClass *rc;
2625 gpointer* key, *mp_key;
2627 key = create_remote_class_key (remote_class, extra_class);
2628 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2634 mp_key = copy_remote_class_key (domain, key);
2638 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2640 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2641 rc->proxy_class = remote_class->proxy_class;
2642 rc->interface_count = remote_class->interface_count + 1;
2644 // Keep the list of interfaces sorted, since the hash key of
2645 // the remote class depends on this
2646 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2647 if (remote_class->interfaces [i] > extra_class && i == j)
2648 rc->interfaces [j++] = extra_class;
2649 rc->interfaces [j] = remote_class->interfaces [i];
2652 rc->interfaces [j] = extra_class;
2654 // Replace the old class. The interface array is the same
2655 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2656 rc->proxy_class = extra_class;
2657 rc->interface_count = remote_class->interface_count;
2658 if (rc->interface_count > 0)
2659 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2662 rc->default_vtable = NULL;
2663 rc->xdomain_vtable = NULL;
2664 rc->proxy_class_name = remote_class->proxy_class_name;
2666 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2672 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2674 MONO_REQ_GC_UNSAFE_MODE;
2676 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2677 mono_domain_lock (domain);
2678 if (rp->target_domain_id != -1) {
2679 if (remote_class->xdomain_vtable == NULL)
2680 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2681 mono_domain_unlock (domain);
2682 mono_loader_unlock ();
2683 return remote_class->xdomain_vtable;
2685 if (remote_class->default_vtable == NULL) {
2688 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2689 klass = mono_class_from_mono_type (type);
2691 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)))
2692 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2695 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2698 mono_domain_unlock (domain);
2699 mono_loader_unlock ();
2700 return remote_class->default_vtable;
2704 * mono_upgrade_remote_class:
2705 * @domain: the application domain
2706 * @tproxy: the proxy whose remote class has to be upgraded.
2707 * @klass: class to which the remote class can be casted.
2709 * Updates the vtable of the remote class by adding the necessary method slots
2710 * and interface offsets so it can be safely casted to klass. klass can be a
2711 * class or an interface.
2714 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2716 MONO_REQ_GC_UNSAFE_MODE;
2718 MonoTransparentProxy *tproxy;
2719 MonoRemoteClass *remote_class;
2720 gboolean redo_vtable;
2722 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2723 mono_domain_lock (domain);
2725 tproxy = (MonoTransparentProxy*) proxy_object;
2726 remote_class = tproxy->remote_class;
2728 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2731 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2732 if (remote_class->interfaces [i] == klass)
2733 redo_vtable = FALSE;
2736 redo_vtable = (remote_class->proxy_class != klass);
2740 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2741 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2744 mono_domain_unlock (domain);
2745 mono_loader_unlock ();
2747 #endif /* DISABLE_REMOTING */
2751 * mono_object_get_virtual_method:
2752 * @obj: object to operate on.
2755 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2756 * the instance of a callvirt of method.
2759 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2761 MONO_REQ_GC_UNSAFE_MODE;
2764 MonoMethod **vtable;
2765 gboolean is_proxy = FALSE;
2766 MonoMethod *res = NULL;
2768 klass = mono_object_class (obj);
2769 #ifndef DISABLE_REMOTING
2770 if (klass == mono_defaults.transparent_proxy_class) {
2771 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2776 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2779 mono_class_setup_vtable (klass);
2780 vtable = klass->vtable;
2782 if (method->slot == -1) {
2783 /* method->slot might not be set for instances of generic methods */
2784 if (method->is_inflated) {
2785 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2786 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2789 g_assert_not_reached ();
2793 /* check method->slot is a valid index: perform isinstance? */
2794 if (method->slot != -1) {
2795 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2797 gboolean variance_used = FALSE;
2798 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2799 g_assert (iface_offset > 0);
2800 res = vtable [iface_offset + method->slot];
2803 res = vtable [method->slot];
2807 #ifndef DISABLE_REMOTING
2809 /* It may be an interface, abstract class method or generic method */
2810 if (!res || mono_method_signature (res)->generic_param_count)
2813 /* generic methods demand invoke_with_check */
2814 if (mono_method_signature (res)->generic_param_count)
2815 res = mono_marshal_get_remoting_invoke_with_check (res);
2818 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2819 res = mono_cominterop_get_invoke (res);
2822 res = mono_marshal_get_remoting_invoke (res);
2827 if (method->is_inflated) {
2829 /* Have to inflate the result */
2830 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2831 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2841 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2843 g_error ("runtime invoke called on uninitialized runtime");
2847 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2850 * mono_runtime_invoke:
2851 * @method: method to invoke
2852 * @obJ: object instance
2853 * @params: arguments to the method
2854 * @exc: exception information.
2856 * Invokes the method represented by @method on the object @obj.
2858 * obj is the 'this' pointer, it should be NULL for static
2859 * methods, a MonoObject* for object instances and a pointer to
2860 * the value type for value types.
2862 * The params array contains the arguments to the method with the
2863 * same convention: MonoObject* pointers for object instances and
2864 * pointers to the value type otherwise.
2866 * From unmanaged code you'll usually use the
2867 * mono_runtime_invoke() variant.
2869 * Note that this function doesn't handle virtual methods for
2870 * you, it will exec the exact method you pass: we still need to
2871 * expose a function to lookup the derived class implementation
2872 * of a virtual method (there are examples of this in the code,
2875 * You can pass NULL as the exc argument if you don't want to
2876 * catch exceptions, otherwise, *exc will be set to the exception
2877 * thrown, if any. if an exception is thrown, you can't use the
2878 * MonoObject* result from the function.
2880 * If the method returns a value type, it is boxed in an object
2884 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2886 MONO_REQ_GC_UNSAFE_MODE;
2890 if (mono_runtime_get_no_exec ())
2891 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2893 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2894 mono_profiler_method_start_invoke (method);
2896 result = default_mono_runtime_invoke (method, obj, params, exc);
2898 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2899 mono_profiler_method_end_invoke (method);
2905 * mono_method_get_unmanaged_thunk:
2906 * @method: method to generate a thunk for.
2908 * Returns an unmanaged->managed thunk that can be used to call
2909 * a managed method directly from C.
2911 * The thunk's C signature closely matches the managed signature:
2913 * C#: public bool Equals (object obj);
2914 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2915 * MonoObject*, MonoException**);
2917 * The 1st ("this") parameter must not be used with static methods:
2919 * C#: public static bool ReferenceEquals (object a, object b);
2920 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2923 * The last argument must be a non-null pointer of a MonoException* pointer.
2924 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2925 * exception has been thrown in managed code. Otherwise it will point
2926 * to the MonoException* caught by the thunk. In this case, the result of
2927 * the thunk is undefined:
2929 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2930 * MonoException *ex = NULL;
2931 * Equals func = mono_method_get_unmanaged_thunk (method);
2932 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2934 * // handle exception
2937 * The calling convention of the thunk matches the platform's default
2938 * convention. This means that under Windows, C declarations must
2939 * contain the __stdcall attribute:
2941 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2942 * MonoObject*, MonoException**);
2946 * Value type arguments and return values are treated as they were objects:
2948 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2949 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2951 * Arguments must be properly boxed upon trunk's invocation, while return
2952 * values must be unboxed.
2955 mono_method_get_unmanaged_thunk (MonoMethod *method)
2957 MONO_REQ_GC_NEUTRAL_MODE;
2958 MONO_REQ_API_ENTRYPOINT;
2962 MONO_PREPARE_RESET_BLOCKING;
2963 method = mono_marshal_get_thunk_invoke_wrapper (method);
2964 res = mono_compile_method (method);
2965 MONO_FINISH_RESET_BLOCKING;
2971 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2973 MONO_REQ_GC_UNSAFE_MODE;
2977 /* object fields cannot be byref, so we don't need a
2979 gpointer *p = (gpointer*)dest;
2986 case MONO_TYPE_BOOLEAN:
2988 case MONO_TYPE_U1: {
2989 guint8 *p = (guint8*)dest;
2990 *p = value ? *(guint8*)value : 0;
2995 case MONO_TYPE_CHAR: {
2996 guint16 *p = (guint16*)dest;
2997 *p = value ? *(guint16*)value : 0;
3000 #if SIZEOF_VOID_P == 4
3005 case MONO_TYPE_U4: {
3006 gint32 *p = (gint32*)dest;
3007 *p = value ? *(gint32*)value : 0;
3010 #if SIZEOF_VOID_P == 8
3015 case MONO_TYPE_U8: {
3016 gint64 *p = (gint64*)dest;
3017 *p = value ? *(gint64*)value : 0;
3020 case MONO_TYPE_R4: {
3021 float *p = (float*)dest;
3022 *p = value ? *(float*)value : 0;
3025 case MONO_TYPE_R8: {
3026 double *p = (double*)dest;
3027 *p = value ? *(double*)value : 0;
3030 case MONO_TYPE_STRING:
3031 case MONO_TYPE_SZARRAY:
3032 case MONO_TYPE_CLASS:
3033 case MONO_TYPE_OBJECT:
3034 case MONO_TYPE_ARRAY:
3035 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3037 case MONO_TYPE_FNPTR:
3038 case MONO_TYPE_PTR: {
3039 gpointer *p = (gpointer*)dest;
3040 *p = deref_pointer? *(gpointer*)value: value;
3043 case MONO_TYPE_VALUETYPE:
3044 /* note that 't' and 'type->type' can be different */
3045 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3046 t = mono_class_enum_basetype (type->data.klass)->type;
3049 MonoClass *klass = mono_class_from_mono_type (type);
3050 int size = mono_class_value_size (klass, NULL);
3052 mono_gc_bzero_atomic (dest, size);
3054 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3057 case MONO_TYPE_GENERICINST:
3058 t = type->data.generic_class->container_class->byval_arg.type;
3061 g_error ("got type %x", type->type);
3066 * mono_field_set_value:
3067 * @obj: Instance object
3068 * @field: MonoClassField describing the field to set
3069 * @value: The value to be set
3071 * Sets the value of the field described by @field in the object instance @obj
3072 * to the value passed in @value. This method should only be used for instance
3073 * fields. For static fields, use mono_field_static_set_value.
3075 * The value must be on the native format of the field type.
3078 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3080 MONO_REQ_GC_UNSAFE_MODE;
3084 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3086 dest = (char*)obj + field->offset;
3087 mono_copy_value (field->type, dest, value, FALSE);
3091 * mono_field_static_set_value:
3092 * @field: MonoClassField describing the field to set
3093 * @value: The value to be set
3095 * Sets the value of the static field described by @field
3096 * to the value passed in @value.
3098 * The value must be on the native format of the field type.
3101 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3103 MONO_REQ_GC_UNSAFE_MODE;
3107 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3108 /* you cant set a constant! */
3109 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3111 if (field->offset == -1) {
3112 /* Special static */
3115 mono_domain_lock (vt->domain);
3116 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3117 mono_domain_unlock (vt->domain);
3118 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3120 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3122 mono_copy_value (field->type, dest, value, FALSE);
3126 * mono_vtable_get_static_field_data:
3128 * Internal use function: return a pointer to the memory holding the static fields
3129 * for a class or NULL if there are no static fields.
3130 * This is exported only for use by the debugger.
3133 mono_vtable_get_static_field_data (MonoVTable *vt)
3135 MONO_REQ_GC_NEUTRAL_MODE
3137 if (!vt->has_static_fields)
3139 return vt->vtable [vt->klass->vtable_size];
3143 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3145 MONO_REQ_GC_UNSAFE_MODE;
3149 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3150 if (field->offset == -1) {
3151 /* Special static */
3154 mono_domain_lock (vt->domain);
3155 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3156 mono_domain_unlock (vt->domain);
3157 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3159 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3162 src = (guint8*)obj + field->offset;
3169 * mono_field_get_value:
3170 * @obj: Object instance
3171 * @field: MonoClassField describing the field to fetch information from
3172 * @value: pointer to the location where the value will be stored
3174 * Use this routine to get the value of the field @field in the object
3177 * The pointer provided by value must be of the field type, for reference
3178 * types this is a MonoObject*, for value types its the actual pointer to
3183 * mono_field_get_value (obj, int_field, &i);
3186 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3188 MONO_REQ_GC_UNSAFE_MODE;
3194 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3196 src = (char*)obj + field->offset;
3197 mono_copy_value (field->type, value, src, TRUE);
3201 * mono_field_get_value_object:
3202 * @domain: domain where the object will be created (if boxing)
3203 * @field: MonoClassField describing the field to fetch information from
3204 * @obj: The object instance for the field.
3206 * Returns: a new MonoObject with the value from the given field. If the
3207 * field represents a value type, the value is boxed.
3211 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3213 MONO_REQ_GC_UNSAFE_MODE;
3217 MonoVTable *vtable = NULL;
3219 gboolean is_static = FALSE;
3220 gboolean is_ref = FALSE;
3221 gboolean is_literal = FALSE;
3222 gboolean is_ptr = FALSE;
3224 MonoType *type = mono_field_get_type_checked (field, &error);
3226 if (!mono_error_ok (&error))
3227 mono_error_raise_exception (&error);
3229 switch (type->type) {
3230 case MONO_TYPE_STRING:
3231 case MONO_TYPE_OBJECT:
3232 case MONO_TYPE_CLASS:
3233 case MONO_TYPE_ARRAY:
3234 case MONO_TYPE_SZARRAY:
3239 case MONO_TYPE_BOOLEAN:
3242 case MONO_TYPE_CHAR:
3251 case MONO_TYPE_VALUETYPE:
3252 is_ref = type->byref;
3254 case MONO_TYPE_GENERICINST:
3255 is_ref = !mono_type_generic_inst_is_valuetype (type);
3261 g_error ("type 0x%x not handled in "
3262 "mono_field_get_value_object", type->type);
3266 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3269 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3273 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3274 if (!vtable->initialized)
3275 mono_runtime_class_init (vtable);
3283 get_default_field_value (domain, field, &o);
3284 } else if (is_static) {
3285 mono_field_static_get_value (vtable, field, &o);
3287 mono_field_get_value (obj, field, &o);
3293 static MonoMethod *m;
3299 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3300 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3306 get_default_field_value (domain, field, v);
3307 } else if (is_static) {
3308 mono_field_static_get_value (vtable, field, v);
3310 mono_field_get_value (obj, field, v);
3313 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3314 args [0] = ptr ? *ptr : NULL;
3315 args [1] = mono_type_get_object (mono_domain_get (), type);
3317 return mono_runtime_invoke (m, NULL, args, NULL);
3320 /* boxed value type */
3321 klass = mono_class_from_mono_type (type);
3323 if (mono_class_is_nullable (klass))
3324 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3326 o = mono_object_new (domain, klass);
3327 v = ((gchar *) o) + sizeof (MonoObject);
3330 get_default_field_value (domain, field, v);
3331 } else if (is_static) {
3332 mono_field_static_get_value (vtable, field, v);
3334 mono_field_get_value (obj, field, v);
3341 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3343 MONO_REQ_GC_UNSAFE_MODE;
3346 const char *p = blob;
3347 mono_metadata_decode_blob_size (p, &p);
3350 case MONO_TYPE_BOOLEAN:
3353 *(guint8 *) value = *p;
3355 case MONO_TYPE_CHAR:
3358 *(guint16*) value = read16 (p);
3362 *(guint32*) value = read32 (p);
3366 *(guint64*) value = read64 (p);
3369 readr4 (p, (float*) value);
3372 readr8 (p, (double*) value);
3374 case MONO_TYPE_STRING:
3375 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3377 case MONO_TYPE_CLASS:
3378 *(gpointer*) value = NULL;
3382 g_warning ("type 0x%02x should not be in constant table", type);
3388 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3390 MONO_REQ_GC_NEUTRAL_MODE;
3392 MonoTypeEnum def_type;
3395 data = mono_class_get_field_default_value (field, &def_type);
3396 mono_get_constant_value_from_blob (domain, def_type, data, value);
3400 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3402 MONO_REQ_GC_UNSAFE_MODE;
3406 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3408 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3409 get_default_field_value (vt->domain, field, value);
3413 if (field->offset == -1) {
3414 /* Special static */
3415 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3416 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3418 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3420 mono_copy_value (field->type, value, src, TRUE);
3424 * mono_field_static_get_value:
3425 * @vt: vtable to the object
3426 * @field: MonoClassField describing the field to fetch information from
3427 * @value: where the value is returned
3429 * Use this routine to get the value of the static field @field value.
3431 * The pointer provided by value must be of the field type, for reference
3432 * types this is a MonoObject*, for value types its the actual pointer to
3437 * mono_field_static_get_value (vt, int_field, &i);
3440 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3442 MONO_REQ_GC_NEUTRAL_MODE;
3444 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3448 * mono_property_set_value:
3449 * @prop: MonoProperty to set
3450 * @obj: instance object on which to act
3451 * @params: parameters to pass to the propery
3452 * @exc: optional exception
3454 * Invokes the property's set method with the given arguments on the
3455 * object instance obj (or NULL for static properties).
3457 * You can pass NULL as the exc argument if you don't want to
3458 * catch exceptions, otherwise, *exc will be set to the exception
3459 * thrown, if any. if an exception is thrown, you can't use the
3460 * MonoObject* result from the function.
3463 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3465 MONO_REQ_GC_UNSAFE_MODE;
3467 default_mono_runtime_invoke (prop->set, obj, params, exc);
3471 * mono_property_get_value:
3472 * @prop: MonoProperty to fetch
3473 * @obj: instance object on which to act
3474 * @params: parameters to pass to the propery
3475 * @exc: optional exception
3477 * Invokes the property's get method with the given arguments on the
3478 * object instance obj (or NULL for static properties).
3480 * You can pass NULL as the exc argument if you don't want to
3481 * catch exceptions, otherwise, *exc will be set to the exception
3482 * thrown, if any. if an exception is thrown, you can't use the
3483 * MonoObject* result from the function.
3485 * Returns: the value from invoking the get method on the property.
3488 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3490 MONO_REQ_GC_UNSAFE_MODE;
3492 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3496 * mono_nullable_init:
3497 * @buf: The nullable structure to initialize.
3498 * @value: the value to initialize from
3499 * @klass: the type for the object
3501 * Initialize the nullable structure pointed to by @buf from @value which
3502 * should be a boxed value type. The size of @buf should be able to hold
3503 * as much data as the @klass->instance_size (which is the number of bytes
3504 * that will be copies).
3506 * Since Nullables have variable structure, we can not define a C
3507 * structure for them.
3510 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3512 MONO_REQ_GC_UNSAFE_MODE;
3514 MonoClass *param_class = klass->cast_class;
3516 mono_class_setup_fields_locking (klass);
3517 g_assert (klass->fields_inited);
3519 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3520 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3522 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3524 if (param_class->has_references)
3525 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3527 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3529 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3534 * mono_nullable_box:
3535 * @buf: The buffer representing the data to be boxed
3536 * @klass: the type to box it as.
3538 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3542 mono_nullable_box (guint8 *buf, MonoClass *klass)
3544 MONO_REQ_GC_UNSAFE_MODE;
3546 MonoClass *param_class = klass->cast_class;
3548 mono_class_setup_fields_locking (klass);
3549 g_assert (klass->fields_inited);
3551 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3552 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3554 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3555 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3556 if (param_class->has_references)
3557 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3559 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3567 * mono_get_delegate_invoke:
3568 * @klass: The delegate class
3570 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3573 mono_get_delegate_invoke (MonoClass *klass)
3575 MONO_REQ_GC_NEUTRAL_MODE;
3579 /* This is called at runtime, so avoid the slower search in metadata */
3580 mono_class_setup_methods (klass);
3581 if (klass->exception_type)
3583 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3588 * mono_get_delegate_begin_invoke:
3589 * @klass: The delegate class
3591 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3594 mono_get_delegate_begin_invoke (MonoClass *klass)
3596 MONO_REQ_GC_NEUTRAL_MODE;
3600 /* This is called at runtime, so avoid the slower search in metadata */
3601 mono_class_setup_methods (klass);
3602 if (klass->exception_type)
3604 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3609 * mono_get_delegate_end_invoke:
3610 * @klass: The delegate class
3612 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3615 mono_get_delegate_end_invoke (MonoClass *klass)
3617 MONO_REQ_GC_NEUTRAL_MODE;
3621 /* This is called at runtime, so avoid the slower search in metadata */
3622 mono_class_setup_methods (klass);
3623 if (klass->exception_type)
3625 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3630 * mono_runtime_delegate_invoke:
3631 * @delegate: pointer to a delegate object.
3632 * @params: parameters for the delegate.
3633 * @exc: Pointer to the exception result.
3635 * Invokes the delegate method @delegate with the parameters provided.
3637 * You can pass NULL as the exc argument if you don't want to
3638 * catch exceptions, otherwise, *exc will be set to the exception
3639 * thrown, if any. if an exception is thrown, you can't use the
3640 * MonoObject* result from the function.
3643 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3645 MONO_REQ_GC_UNSAFE_MODE;
3648 MonoClass *klass = delegate->vtable->klass;
3650 im = mono_get_delegate_invoke (klass);
3652 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3654 return mono_runtime_invoke (im, delegate, params, exc);
3657 static char **main_args = NULL;
3658 static int num_main_args = 0;
3661 * mono_runtime_get_main_args:
3663 * Returns: a MonoArray with the arguments passed to the main program
3666 mono_runtime_get_main_args (void)
3668 MONO_REQ_GC_UNSAFE_MODE;
3672 MonoDomain *domain = mono_domain_get ();
3674 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3676 for (i = 0; i < num_main_args; ++i)
3677 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3683 free_main_args (void)
3685 MONO_REQ_GC_NEUTRAL_MODE;
3689 for (i = 0; i < num_main_args; ++i)
3690 g_free (main_args [i]);
3697 * mono_runtime_set_main_args:
3698 * @argc: number of arguments from the command line
3699 * @argv: array of strings from the command line
3701 * Set the command line arguments from an embedding application that doesn't otherwise call
3702 * mono_runtime_run_main ().
3705 mono_runtime_set_main_args (int argc, char* argv[])
3707 MONO_REQ_GC_NEUTRAL_MODE;
3712 main_args = g_new0 (char*, argc);
3713 num_main_args = argc;
3715 for (i = 0; i < argc; ++i) {
3718 utf8_arg = mono_utf8_from_external (argv[i]);
3719 if (utf8_arg == NULL) {
3720 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3721 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3725 main_args [i] = utf8_arg;
3732 * mono_runtime_run_main:
3733 * @method: the method to start the application with (usually Main)
3734 * @argc: number of arguments from the command line
3735 * @argv: array of strings from the command line
3736 * @exc: excetption results
3738 * Execute a standard Main() method (argc/argv contains the
3739 * executable name). This method also sets the command line argument value
3740 * needed by System.Environment.
3745 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3748 MONO_REQ_GC_UNSAFE_MODE;
3751 MonoArray *args = NULL;
3752 MonoDomain *domain = mono_domain_get ();
3753 gchar *utf8_fullpath;
3754 MonoMethodSignature *sig;
3756 g_assert (method != NULL);
3758 mono_thread_set_main (mono_thread_current ());
3760 main_args = g_new0 (char*, argc);
3761 num_main_args = argc;
3763 if (!g_path_is_absolute (argv [0])) {
3764 gchar *basename = g_path_get_basename (argv [0]);
3765 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3769 utf8_fullpath = mono_utf8_from_external (fullpath);
3770 if(utf8_fullpath == NULL) {
3771 /* Printing the arg text will cause glib to
3772 * whinge about "Invalid UTF-8", but at least
3773 * its relevant, and shows the problem text
3776 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3777 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3784 utf8_fullpath = mono_utf8_from_external (argv[0]);
3785 if(utf8_fullpath == NULL) {
3786 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3787 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3792 main_args [0] = utf8_fullpath;
3794 for (i = 1; i < argc; ++i) {
3797 utf8_arg=mono_utf8_from_external (argv[i]);
3798 if(utf8_arg==NULL) {
3799 /* Ditto the comment about Invalid UTF-8 here */
3800 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3801 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3805 main_args [i] = utf8_arg;
3810 sig = mono_method_signature (method);
3812 g_print ("Unable to load Main method.\n");
3816 if (sig->param_count) {
3817 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3818 for (i = 0; i < argc; ++i) {
3819 /* The encodings should all work, given that
3820 * we've checked all these args for the
3823 gchar *str = mono_utf8_from_external (argv [i]);
3824 MonoString *arg = mono_string_new (domain, str);
3825 mono_array_setref (args, i, arg);
3829 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3832 mono_assembly_set_main (method->klass->image->assembly);
3834 return mono_runtime_exec_main (method, args, exc);
3838 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3840 static MonoMethod *serialize_method;
3845 if (!serialize_method) {
3846 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3847 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3850 if (!serialize_method) {
3855 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3859 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3867 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3869 MONO_REQ_GC_UNSAFE_MODE;
3871 static MonoMethod *deserialize_method;
3876 if (!deserialize_method) {
3877 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3878 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3880 if (!deserialize_method) {
3887 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3894 #ifndef DISABLE_REMOTING
3896 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3898 MONO_REQ_GC_UNSAFE_MODE;
3900 static MonoMethod *get_proxy_method;
3902 MonoDomain *domain = mono_domain_get ();
3903 MonoRealProxy *real_proxy;
3904 MonoReflectionType *reflection_type;
3905 MonoTransparentProxy *transparent_proxy;
3907 if (!get_proxy_method)
3908 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3910 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3912 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3913 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3915 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3916 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3919 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3923 return (MonoObject*) transparent_proxy;
3925 #endif /* DISABLE_REMOTING */
3928 * mono_object_xdomain_representation
3930 * @target_domain: a domain
3931 * @exc: pointer to a MonoObject*
3933 * Creates a representation of obj in the domain target_domain. This
3934 * is either a copy of obj arrived through via serialization and
3935 * deserialization or a proxy, depending on whether the object is
3936 * serializable or marshal by ref. obj must not be in target_domain.
3938 * If the object cannot be represented in target_domain, NULL is
3939 * returned and *exc is set to an appropriate exception.
3942 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3944 MONO_REQ_GC_UNSAFE_MODE;
3946 MonoObject *deserialized = NULL;
3947 gboolean failure = FALSE;
3951 #ifndef DISABLE_REMOTING
3952 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3953 deserialized = make_transparent_proxy (obj, &failure, exc);
3958 MonoDomain *domain = mono_domain_get ();
3959 MonoObject *serialized;
3961 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3962 serialized = serialize_object (obj, &failure, exc);
3963 mono_domain_set_internal_with_options (target_domain, FALSE);
3965 deserialized = deserialize_object (serialized, &failure, exc);
3966 if (domain != target_domain)
3967 mono_domain_set_internal_with_options (domain, FALSE);
3970 return deserialized;
3973 /* Used in call_unhandled_exception_delegate */
3975 create_unhandled_exception_eventargs (MonoObject *exc)
3977 MONO_REQ_GC_UNSAFE_MODE;
3981 MonoMethod *method = NULL;
3982 MonoBoolean is_terminating = TRUE;
3985 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3988 mono_class_init (klass);
3990 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3991 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3995 args [1] = &is_terminating;
3997 obj = mono_object_new (mono_domain_get (), klass);
3998 mono_runtime_invoke (method, obj, args, NULL);
4003 /* Used in mono_unhandled_exception */
4005 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4006 MONO_REQ_GC_UNSAFE_MODE;
4008 MonoObject *e = NULL;
4010 MonoDomain *current_domain = mono_domain_get ();
4012 if (domain != current_domain)
4013 mono_domain_set_internal_with_options (domain, FALSE);
4015 g_assert (domain == mono_object_domain (domain->domain));
4017 if (mono_object_domain (exc) != domain) {
4018 MonoObject *serialization_exc;
4020 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4022 if (serialization_exc) {
4024 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4027 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4028 "System.Runtime.Serialization", "SerializationException",
4029 "Could not serialize unhandled exception.");
4033 g_assert (mono_object_domain (exc) == domain);
4035 pa [0] = domain->domain;
4036 pa [1] = create_unhandled_exception_eventargs (exc);
4037 mono_runtime_delegate_invoke (delegate, pa, &e);
4039 if (domain != current_domain)
4040 mono_domain_set_internal_with_options (current_domain, FALSE);
4044 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4045 if (!mono_error_ok (&error)) {
4046 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4047 mono_error_cleanup (&error);
4049 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4055 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4058 * mono_runtime_unhandled_exception_policy_set:
4059 * @policy: the new policy
4061 * This is a VM internal routine.
4063 * Sets the runtime policy for handling unhandled exceptions.
4066 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4067 runtime_unhandled_exception_policy = policy;
4071 * mono_runtime_unhandled_exception_policy_get:
4073 * This is a VM internal routine.
4075 * Gets the runtime policy for handling unhandled exceptions.
4077 MonoRuntimeUnhandledExceptionPolicy
4078 mono_runtime_unhandled_exception_policy_get (void) {
4079 return runtime_unhandled_exception_policy;
4083 * mono_unhandled_exception:
4084 * @exc: exception thrown
4086 * This is a VM internal routine.
4088 * We call this function when we detect an unhandled exception
4089 * in the default domain.
4091 * It invokes the * UnhandledException event in AppDomain or prints
4092 * a warning to the console
4095 mono_unhandled_exception (MonoObject *exc)
4097 MONO_REQ_GC_UNSAFE_MODE;
4099 MonoClassField *field;
4100 MonoDomain *current_domain, *root_domain;
4101 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4103 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4106 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4109 current_domain = mono_domain_get ();
4110 root_domain = mono_get_root_domain ();
4112 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4113 if (current_domain != root_domain)
4114 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4116 /* set exitcode only if we will abort the process */
4117 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4118 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4119 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4121 mono_environment_exitcode_set (1);
4124 mono_print_unhandled_exception (exc);
4126 if (root_appdomain_delegate)
4127 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4128 if (current_appdomain_delegate)
4129 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4134 * mono_runtime_exec_managed_code:
4135 * @domain: Application domain
4136 * @main_func: function to invoke from the execution thread
4137 * @main_args: parameter to the main_func
4139 * Launch a new thread to execute a function
4141 * main_func is called back from the thread with main_args as the
4142 * parameter. The callback function is expected to start Main()
4143 * eventually. This function then waits for all managed threads to
4145 * It is not necesseray anymore to execute managed code in a subthread,
4146 * so this function should not be used anymore by default: just
4147 * execute the code and then call mono_thread_manage ().
4150 mono_runtime_exec_managed_code (MonoDomain *domain,
4151 MonoMainThreadFunc main_func,
4154 mono_thread_create (domain, main_func, main_args);
4156 mono_thread_manage ();
4160 * Execute a standard Main() method (args doesn't contain the
4164 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4166 MONO_REQ_GC_UNSAFE_MODE;
4171 MonoCustomAttrInfo* cinfo;
4172 gboolean has_stathread_attribute;
4173 MonoInternalThread* thread = mono_thread_internal_current ();
4179 domain = mono_object_domain (args);
4180 if (!domain->entry_assembly) {
4182 MonoAssembly *assembly;
4184 assembly = method->klass->image->assembly;
4185 domain->entry_assembly = assembly;
4186 /* Domains created from another domain already have application_base and configuration_file set */
4187 if (domain->setup->application_base == NULL) {
4188 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4191 if (domain->setup->configuration_file == NULL) {
4192 str = g_strconcat (assembly->image->name, ".config", NULL);
4193 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4195 mono_set_private_bin_path_from_config (domain);
4199 cinfo = mono_custom_attrs_from_method (method);
4201 static MonoClass *stathread_attribute = NULL;
4202 if (!stathread_attribute)
4203 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4204 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4206 mono_custom_attrs_free (cinfo);
4208 has_stathread_attribute = FALSE;
4210 if (has_stathread_attribute) {
4211 thread->apartment_state = ThreadApartmentState_STA;
4213 thread->apartment_state = ThreadApartmentState_MTA;
4215 mono_thread_init_apartment_state ();
4217 /* FIXME: check signature of method */
4218 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4220 res = mono_runtime_invoke (method, NULL, pa, exc);
4222 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4226 mono_environment_exitcode_set (rval);
4228 mono_runtime_invoke (method, NULL, pa, exc);
4232 /* If the return type of Main is void, only
4233 * set the exitcode if an exception was thrown
4234 * (we don't want to blow away an
4235 * explicitly-set exit code)
4238 mono_environment_exitcode_set (rval);
4246 * mono_install_runtime_invoke:
4247 * @func: Function to install
4249 * This is a VM internal routine
4252 mono_install_runtime_invoke (MonoInvokeFunc func)
4254 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4259 * mono_runtime_invoke_array:
4260 * @method: method to invoke
4261 * @obJ: object instance
4262 * @params: arguments to the method
4263 * @exc: exception information.
4265 * Invokes the method represented by @method on the object @obj.
4267 * obj is the 'this' pointer, it should be NULL for static
4268 * methods, a MonoObject* for object instances and a pointer to
4269 * the value type for value types.
4271 * The params array contains the arguments to the method with the
4272 * same convention: MonoObject* pointers for object instances and
4273 * pointers to the value type otherwise. The _invoke_array
4274 * variant takes a C# object[] as the params argument (MonoArray
4275 * *params): in this case the value types are boxed inside the
4276 * respective reference representation.
4278 * From unmanaged code you'll usually use the
4279 * mono_runtime_invoke() variant.
4281 * Note that this function doesn't handle virtual methods for
4282 * you, it will exec the exact method you pass: we still need to
4283 * expose a function to lookup the derived class implementation
4284 * of a virtual method (there are examples of this in the code,
4287 * You can pass NULL as the exc argument if you don't want to
4288 * catch exceptions, otherwise, *exc will be set to the exception
4289 * thrown, if any. if an exception is thrown, you can't use the
4290 * MonoObject* result from the function.
4292 * If the method returns a value type, it is boxed in an object
4296 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4299 MONO_REQ_GC_UNSAFE_MODE;
4301 MonoMethodSignature *sig = mono_method_signature (method);
4302 gpointer *pa = NULL;
4305 gboolean has_byref_nullables = FALSE;
4307 if (NULL != params) {
4308 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4309 for (i = 0; i < mono_array_length (params); i++) {
4310 MonoType *t = sig->params [i];
4316 case MONO_TYPE_BOOLEAN:
4319 case MONO_TYPE_CHAR:
4328 case MONO_TYPE_VALUETYPE:
4329 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4330 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4331 pa [i] = mono_array_get (params, MonoObject*, i);
4333 has_byref_nullables = TRUE;
4335 /* MS seems to create the objects if a null is passed in */
4336 if (!mono_array_get (params, MonoObject*, i))
4337 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4341 * We can't pass the unboxed vtype byref to the callee, since
4342 * that would mean the callee would be able to modify boxed
4343 * primitive types. So we (and MS) make a copy of the boxed
4344 * object, pass that to the callee, and replace the original
4345 * boxed object in the arg array with the copy.
4347 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4348 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4349 mono_array_setref (params, i, copy);
4352 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4355 case MONO_TYPE_STRING:
4356 case MONO_TYPE_OBJECT:
4357 case MONO_TYPE_CLASS:
4358 case MONO_TYPE_ARRAY:
4359 case MONO_TYPE_SZARRAY:
4361 pa [i] = mono_array_addr (params, MonoObject*, i);
4362 // FIXME: I need to check this code path
4364 pa [i] = mono_array_get (params, MonoObject*, i);
4366 case MONO_TYPE_GENERICINST:
4368 t = &t->data.generic_class->container_class->this_arg;
4370 t = &t->data.generic_class->container_class->byval_arg;
4372 case MONO_TYPE_PTR: {
4375 /* The argument should be an IntPtr */
4376 arg = mono_array_get (params, MonoObject*, i);
4380 g_assert (arg->vtable->klass == mono_defaults.int_class);
4381 pa [i] = ((MonoIntPtr*)arg)->m_value;
4386 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4391 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4394 if (mono_class_is_nullable (method->klass)) {
4395 /* Need to create a boxed vtype instead */
4401 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4405 obj = mono_object_new (mono_domain_get (), method->klass);
4406 g_assert (obj); /*maybe we should raise a TLE instead?*/
4407 #ifndef DISABLE_REMOTING
4408 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4409 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4412 if (method->klass->valuetype)
4413 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4416 } else if (method->klass->valuetype) {
4417 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4420 mono_runtime_invoke (method, o, pa, exc);
4421 return (MonoObject *)obj;
4423 if (mono_class_is_nullable (method->klass)) {
4424 MonoObject *nullable;
4426 /* Convert the unboxed vtype into a Nullable structure */
4427 nullable = mono_object_new (mono_domain_get (), method->klass);
4429 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4430 obj = mono_object_unbox (nullable);
4433 /* obj must be already unboxed if needed */
4434 res = mono_runtime_invoke (method, obj, pa, exc);
4436 if (sig->ret->type == MONO_TYPE_PTR) {
4437 MonoClass *pointer_class;
4438 static MonoMethod *box_method;
4440 MonoObject *box_exc;
4443 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4444 * convert it to a Pointer object.
4446 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4448 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4450 g_assert (res->vtable->klass == mono_defaults.int_class);
4451 box_args [0] = ((MonoIntPtr*)res)->m_value;
4452 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4453 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4454 g_assert (!box_exc);
4457 if (has_byref_nullables) {
4459 * The runtime invoke wrapper already converted byref nullables back,
4460 * and stored them in pa, we just need to copy them back to the
4463 for (i = 0; i < mono_array_length (params); i++) {
4464 MonoType *t = sig->params [i];
4466 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4467 mono_array_setref (params, i, pa [i]);
4476 arith_overflow (void)
4478 MONO_REQ_GC_UNSAFE_MODE;
4480 mono_raise_exception (mono_get_exception_overflow ());
4485 * @klass: the class of the object that we want to create
4487 * Returns: a newly created object whose definition is
4488 * looked up using @klass. This will not invoke any constructors,
4489 * so the consumer of this routine has to invoke any constructors on
4490 * its own to initialize the object.
4492 * It returns NULL on failure.
4495 mono_object_new (MonoDomain *domain, MonoClass *klass)
4497 MONO_REQ_GC_UNSAFE_MODE;
4501 vtable = mono_class_vtable (domain, klass);
4504 return mono_object_new_specific (vtable);
4508 * mono_object_new_pinned:
4510 * Same as mono_object_new, but the returned object will be pinned.
4511 * For SGEN, these objects will only be freed at appdomain unload.
4514 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4516 MONO_REQ_GC_UNSAFE_MODE;
4520 vtable = mono_class_vtable (domain, klass);
4525 return (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4527 return mono_object_new_specific (vtable);
4532 * mono_object_new_specific:
4533 * @vtable: the vtable of the object that we want to create
4535 * Returns: A newly created object with class and domain specified
4539 mono_object_new_specific (MonoVTable *vtable)
4541 MONO_REQ_GC_UNSAFE_MODE;
4545 /* check for is_com_object for COM Interop */
4546 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4549 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4552 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4555 mono_class_init (klass);
4557 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4559 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
4560 vtable->domain->create_proxy_for_type_method = im;
4563 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4565 o = mono_runtime_invoke (im, NULL, pa, NULL);
4566 if (o != NULL) return o;
4569 return mono_object_new_alloc_specific (vtable);
4573 mono_object_new_alloc_specific (MonoVTable *vtable)
4575 MONO_REQ_GC_UNSAFE_MODE;
4577 MonoObject *o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4579 if (G_UNLIKELY (vtable->klass->has_finalize))
4580 mono_object_register_finalizer (o);
4586 mono_object_new_fast (MonoVTable *vtable)
4588 MONO_REQ_GC_UNSAFE_MODE;
4590 return (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4594 * mono_class_get_allocation_ftn:
4596 * @for_box: the object will be used for boxing
4597 * @pass_size_in_words:
4599 * Return the allocation function appropriate for the given class.
4603 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4605 MONO_REQ_GC_NEUTRAL_MODE;
4607 *pass_size_in_words = FALSE;
4609 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4610 return mono_object_new_specific;
4612 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4614 return mono_object_new_fast;
4617 * FIXME: This is actually slower than mono_object_new_fast, because
4618 * of the overhead of parameter passing.
4621 *pass_size_in_words = TRUE;
4622 #ifdef GC_REDIRECT_TO_LOCAL
4623 return GC_local_gcj_fast_malloc;
4625 return GC_gcj_fast_malloc;
4630 return mono_object_new_specific;
4634 * mono_object_new_from_token:
4635 * @image: Context where the type_token is hosted
4636 * @token: a token of the type that we want to create
4638 * Returns: A newly created object whose definition is
4639 * looked up using @token in the @image image
4642 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4644 MONO_REQ_GC_UNSAFE_MODE;
4649 klass = mono_class_get_checked (image, token, &error);
4650 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4652 return mono_object_new (domain, klass);
4657 * mono_object_clone:
4658 * @obj: the object to clone
4660 * Returns: A newly created object who is a shallow copy of @obj
4663 mono_object_clone (MonoObject *obj)
4665 MONO_REQ_GC_UNSAFE_MODE;
4668 int size = obj->vtable->klass->instance_size;
4670 if (obj->vtable->klass->rank)
4671 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4673 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4675 /* If the object doesn't contain references this will do a simple memmove. */
4676 mono_gc_wbarrier_object_copy (o, obj);
4678 if (obj->vtable->klass->has_finalize)
4679 mono_object_register_finalizer (o);
4684 * mono_array_full_copy:
4685 * @src: source array to copy
4686 * @dest: destination array
4688 * Copies the content of one array to another with exactly the same type and size.
4691 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4693 MONO_REQ_GC_UNSAFE_MODE;
4696 MonoClass *klass = src->obj.vtable->klass;
4698 g_assert (klass == dest->obj.vtable->klass);
4700 size = mono_array_length (src);
4701 g_assert (size == mono_array_length (dest));
4702 size *= mono_array_element_size (klass);
4704 if (klass->element_class->valuetype) {
4705 if (klass->element_class->has_references)
4706 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4708 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4710 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4713 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4718 * mono_array_clone_in_domain:
4719 * @domain: the domain in which the array will be cloned into
4720 * @array: the array to clone
4722 * This routine returns a copy of the array that is hosted on the
4723 * specified MonoDomain.
4726 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4728 MONO_REQ_GC_UNSAFE_MODE;
4733 MonoClass *klass = array->obj.vtable->klass;
4735 if (array->bounds == NULL) {
4736 size = mono_array_length (array);
4737 o = mono_array_new_full (domain, klass, &size, NULL);
4739 size *= mono_array_element_size (klass);
4741 if (klass->element_class->valuetype) {
4742 if (klass->element_class->has_references)
4743 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4745 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4747 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4750 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4755 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4756 size = mono_array_element_size (klass);
4757 for (i = 0; i < klass->rank; ++i) {
4758 sizes [i] = array->bounds [i].length;
4759 size *= array->bounds [i].length;
4760 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4762 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4764 if (klass->element_class->valuetype) {
4765 if (klass->element_class->has_references)
4766 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4768 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4770 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4773 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4781 * @array: the array to clone
4783 * Returns: A newly created array who is a shallow copy of @array
4786 mono_array_clone (MonoArray *array)
4788 MONO_REQ_GC_UNSAFE_MODE;
4790 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4793 /* helper macros to check for overflow when calculating the size of arrays */
4794 #ifdef MONO_BIG_ARRAYS
4795 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4796 #define MYGUINT_MAX MYGUINT64_MAX
4797 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4798 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4799 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4800 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4801 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4803 #define MYGUINT32_MAX 4294967295U
4804 #define MYGUINT_MAX MYGUINT32_MAX
4805 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4806 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4807 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4808 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4809 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4813 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4815 MONO_REQ_GC_NEUTRAL_MODE;
4819 byte_len = mono_array_element_size (klass);
4820 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4823 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4825 byte_len += MONO_SIZEOF_MONO_ARRAY;
4833 * mono_array_new_full:
4834 * @domain: domain where the object is created
4835 * @array_class: array class
4836 * @lengths: lengths for each dimension in the array
4837 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4839 * This routine creates a new array objects with the given dimensions,
4840 * lower bounds and type.
4843 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4845 MONO_REQ_GC_UNSAFE_MODE;
4847 uintptr_t byte_len = 0, len, bounds_size;
4850 MonoArrayBounds *bounds;
4854 if (!array_class->inited)
4855 mono_class_init (array_class);
4859 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4860 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4862 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4866 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4868 for (i = 0; i < array_class->rank; ++i) {
4869 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4871 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4872 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4877 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4878 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4882 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4883 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4884 byte_len = (byte_len + 3) & ~3;
4885 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4886 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4887 byte_len += bounds_size;
4890 * Following three lines almost taken from mono_object_new ():
4891 * they need to be kept in sync.
4893 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4895 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4897 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
4898 array = (MonoArray*)o;
4900 bounds = array->bounds;
4903 for (i = 0; i < array_class->rank; ++i) {
4904 bounds [i].length = lengths [i];
4906 bounds [i].lower_bound = lower_bounds [i];
4915 * @domain: domain where the object is created
4916 * @eclass: element class
4917 * @n: number of array elements
4919 * This routine creates a new szarray with @n elements of type @eclass.
4922 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4924 MONO_REQ_GC_UNSAFE_MODE;
4928 ac = mono_array_class_get (eclass, 1);
4931 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4935 * mono_array_new_specific:
4936 * @vtable: a vtable in the appropriate domain for an initialized class
4937 * @n: number of array elements
4939 * This routine is a fast alternative to mono_array_new() for code which
4940 * can be sure about the domain it operates in.
4943 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4945 MONO_REQ_GC_UNSAFE_MODE;
4951 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4956 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4957 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4960 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
4967 * mono_string_new_utf16:
4968 * @text: a pointer to an utf16 string
4969 * @len: the length of the string
4971 * Returns: A newly created string object which contains @text.
4974 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4976 MONO_REQ_GC_UNSAFE_MODE;
4980 s = mono_string_new_size (domain, len);
4981 g_assert (s != NULL);
4983 memcpy (mono_string_chars (s), text, len * 2);
4989 * mono_string_new_utf32:
4990 * @text: a pointer to an utf32 string
4991 * @len: the length of the string
4993 * Returns: A newly created string object which contains @text.
4996 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4998 MONO_REQ_GC_UNSAFE_MODE;
5001 mono_unichar2 *utf16_output = NULL;
5002 gint32 utf16_len = 0;
5003 GError *error = NULL;
5004 glong items_written;
5006 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5009 g_error_free (error);
5011 while (utf16_output [utf16_len]) utf16_len++;
5013 s = mono_string_new_size (domain, utf16_len);
5014 g_assert (s != NULL);
5016 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5018 g_free (utf16_output);
5024 * mono_string_new_size:
5025 * @text: a pointer to an utf16 string
5026 * @len: the length of the string
5028 * Returns: A newly created string object of @len
5031 mono_string_new_size (MonoDomain *domain, gint32 len)
5033 MONO_REQ_GC_UNSAFE_MODE;
5039 /* check for overflow */
5040 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5041 mono_gc_out_of_memory (-1);
5043 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5044 g_assert (size > 0);
5046 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5049 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5055 * mono_string_new_len:
5056 * @text: a pointer to an utf8 string
5057 * @length: number of bytes in @text to consider
5059 * Returns: A newly created string object which contains @text.
5062 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5064 MONO_REQ_GC_UNSAFE_MODE;
5066 GError *error = NULL;
5067 MonoString *o = NULL;
5069 glong items_written;
5071 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5074 o = mono_string_new_utf16 (domain, ut, items_written);
5076 g_error_free (error);
5085 * @text: a pointer to an utf8 string
5087 * Returns: A newly created string object which contains @text.
5090 mono_string_new (MonoDomain *domain, const char *text)
5092 MONO_REQ_GC_UNSAFE_MODE;
5094 GError *error = NULL;
5095 MonoString *o = NULL;
5097 glong items_written;
5102 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5105 o = mono_string_new_utf16 (domain, ut, items_written);
5107 g_error_free (error);
5110 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5115 MonoString *o = NULL;
5117 if (!g_utf8_validate (text, -1, &end))
5120 len = g_utf8_strlen (text, -1);
5121 o = mono_string_new_size (domain, len);
5122 str = mono_string_chars (o);
5124 while (text < end) {
5125 *str++ = g_utf8_get_char (text);
5126 text = g_utf8_next_char (text);
5133 * mono_string_new_wrapper:
5134 * @text: pointer to utf8 characters.
5136 * Helper function to create a string object from @text in the current domain.
5139 mono_string_new_wrapper (const char *text)
5141 MONO_REQ_GC_UNSAFE_MODE;
5143 MonoDomain *domain = mono_domain_get ();
5146 return mono_string_new (domain, text);
5153 * @class: the class of the value
5154 * @value: a pointer to the unboxed data
5156 * Returns: A newly created object which contains @value.
5159 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5161 MONO_REQ_GC_UNSAFE_MODE;
5167 g_assert (klass->valuetype);
5168 if (mono_class_is_nullable (klass))
5169 return mono_nullable_box ((guint8 *)value, klass);
5171 vtable = mono_class_vtable (domain, klass);
5174 size = mono_class_instance_size (klass);
5175 res = mono_object_new_alloc_specific (vtable);
5177 size = size - sizeof (MonoObject);
5180 g_assert (size == mono_class_value_size (klass, NULL));
5181 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5183 #if NO_UNALIGNED_ACCESS
5184 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5188 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5191 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5194 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5197 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5200 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5204 if (klass->has_finalize)
5205 mono_object_register_finalizer (res);
5211 * @dest: destination pointer
5212 * @src: source pointer
5213 * @klass: a valuetype class
5215 * Copy a valuetype from @src to @dest. This function must be used
5216 * when @klass contains references fields.
5219 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5221 MONO_REQ_GC_UNSAFE_MODE;
5223 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5227 * mono_value_copy_array:
5228 * @dest: destination array
5229 * @dest_idx: index in the @dest array
5230 * @src: source pointer
5231 * @count: number of items
5233 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5234 * This function must be used when @klass contains references fields.
5235 * Overlap is handled.
5238 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5240 MONO_REQ_GC_UNSAFE_MODE;
5242 int size = mono_array_element_size (dest->obj.vtable->klass);
5243 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5244 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5245 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5249 * mono_object_get_domain:
5250 * @obj: object to query
5252 * Returns: the MonoDomain where the object is hosted
5255 mono_object_get_domain (MonoObject *obj)
5257 MONO_REQ_GC_UNSAFE_MODE;
5259 return mono_object_domain (obj);
5263 * mono_object_get_class:
5264 * @obj: object to query
5266 * Returns: the MonOClass of the object.
5269 mono_object_get_class (MonoObject *obj)
5271 MONO_REQ_GC_UNSAFE_MODE;
5273 return mono_object_class (obj);
5276 * mono_object_get_size:
5277 * @o: object to query
5279 * Returns: the size, in bytes, of @o
5282 mono_object_get_size (MonoObject* o)
5284 MONO_REQ_GC_UNSAFE_MODE;
5286 MonoClass* klass = mono_object_class (o);
5287 if (klass == mono_defaults.string_class) {
5288 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5289 } else if (o->vtable->rank) {
5290 MonoArray *array = (MonoArray*)o;
5291 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5292 if (array->bounds) {
5295 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5299 return mono_class_instance_size (klass);
5304 * mono_object_unbox:
5305 * @obj: object to unbox
5307 * Returns: a pointer to the start of the valuetype boxed in this
5310 * This method will assert if the object passed is not a valuetype.
5313 mono_object_unbox (MonoObject *obj)
5315 MONO_REQ_GC_UNSAFE_MODE;
5317 /* add assert for valuetypes? */
5318 g_assert (obj->vtable->klass->valuetype);
5319 return ((char*)obj) + sizeof (MonoObject);
5323 * mono_object_isinst:
5325 * @klass: a pointer to a class
5327 * Returns: @obj if @obj is derived from @klass
5330 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5332 MONO_REQ_GC_UNSAFE_MODE;
5335 mono_class_init (klass);
5337 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5338 return mono_object_isinst_mbyref (obj, klass);
5343 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5347 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5349 MONO_REQ_GC_UNSAFE_MODE;
5358 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5359 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5363 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5364 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5367 MonoClass *oklass = vt->klass;
5368 if (mono_class_is_transparent_proxy (oklass))
5369 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5371 mono_class_setup_supertypes (klass);
5372 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5375 #ifndef DISABLE_REMOTING
5376 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5378 MonoDomain *domain = mono_domain_get ();
5380 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5381 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5382 MonoMethod *im = NULL;
5385 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5387 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5388 im = mono_object_get_virtual_method (rp, im);
5391 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5394 res = mono_runtime_invoke (im, rp, pa, NULL);
5396 if (*(MonoBoolean *) mono_object_unbox(res)) {
5397 /* Update the vtable of the remote type, so it can safely cast to this new type */
5398 mono_upgrade_remote_class (domain, obj, klass);
5402 #endif /* DISABLE_REMOTING */
5407 * mono_object_castclass_mbyref:
5409 * @klass: a pointer to a class
5411 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5414 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5416 MONO_REQ_GC_UNSAFE_MODE;
5418 if (!obj) return NULL;
5419 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5421 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5423 "InvalidCastException"));
5428 MonoDomain *orig_domain;
5434 str_lookup (MonoDomain *domain, gpointer user_data)
5436 MONO_REQ_GC_UNSAFE_MODE;
5438 LDStrInfo *info = (LDStrInfo *)user_data;
5439 if (info->res || domain == info->orig_domain)
5441 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5447 mono_string_get_pinned (MonoString *str)
5449 MONO_REQ_GC_UNSAFE_MODE;
5453 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5454 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5456 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5457 news->length = mono_string_length (str);
5463 #define mono_string_get_pinned(str) (str)
5467 mono_string_is_interned_lookup (MonoString *str, int insert)
5469 MONO_REQ_GC_UNSAFE_MODE;
5471 MonoGHashTable *ldstr_table;
5472 MonoString *s, *res;
5475 domain = ((MonoObject *)str)->vtable->domain;
5476 ldstr_table = domain->ldstr_table;
5478 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5484 /* Allocate outside the lock */
5486 s = mono_string_get_pinned (str);
5489 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5494 mono_g_hash_table_insert (ldstr_table, s, s);
5499 LDStrInfo ldstr_info;
5500 ldstr_info.orig_domain = domain;
5501 ldstr_info.ins = str;
5502 ldstr_info.res = NULL;
5504 mono_domain_foreach (str_lookup, &ldstr_info);
5505 if (ldstr_info.res) {
5507 * the string was already interned in some other domain:
5508 * intern it in the current one as well.
5510 mono_g_hash_table_insert (ldstr_table, str, str);
5520 * mono_string_is_interned:
5521 * @o: String to probe
5523 * Returns whether the string has been interned.
5526 mono_string_is_interned (MonoString *o)
5528 MONO_REQ_GC_UNSAFE_MODE;
5530 return mono_string_is_interned_lookup (o, FALSE);
5534 * mono_string_intern:
5535 * @o: String to intern
5537 * Interns the string passed.
5538 * Returns: The interned string.
5541 mono_string_intern (MonoString *str)
5543 MONO_REQ_GC_UNSAFE_MODE;
5545 return mono_string_is_interned_lookup (str, TRUE);
5550 * @domain: the domain where the string will be used.
5551 * @image: a metadata context
5552 * @idx: index into the user string table.
5554 * Implementation for the ldstr opcode.
5555 * Returns: a loaded string from the @image/@idx combination.
5558 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5560 MONO_REQ_GC_UNSAFE_MODE;
5562 if (image->dynamic) {
5563 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5566 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5567 return NULL; /*FIXME we should probably be raising an exception here*/
5568 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5573 * mono_ldstr_metadata_sig
5574 * @domain: the domain for the string
5575 * @sig: the signature of a metadata string
5577 * Returns: a MonoString for a string stored in the metadata
5580 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5582 MONO_REQ_GC_UNSAFE_MODE;
5584 const char *str = sig;
5585 MonoString *o, *interned;
5588 len2 = mono_metadata_decode_blob_size (str, &str);
5591 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5592 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5595 guint16 *p2 = (guint16*)mono_string_chars (o);
5596 for (i = 0; i < len2; ++i) {
5597 *p2 = GUINT16_FROM_LE (*p2);
5603 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5606 return interned; /* o will get garbage collected */
5608 o = mono_string_get_pinned (o);
5611 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5613 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5623 * mono_string_to_utf8:
5624 * @s: a System.String
5626 * Returns the UTF8 representation for @s.
5627 * The resulting buffer needs to be freed with mono_free().
5629 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5632 mono_string_to_utf8 (MonoString *s)
5634 MONO_REQ_GC_UNSAFE_MODE;
5637 char *result = mono_string_to_utf8_checked (s, &error);
5639 if (!mono_error_ok (&error))
5640 mono_error_raise_exception (&error);
5645 * mono_string_to_utf8_checked:
5646 * @s: a System.String
5647 * @error: a MonoError.
5649 * Converts a MonoString to its UTF8 representation. May fail; check
5650 * @error to determine whether the conversion was successful.
5651 * The resulting buffer should be freed with mono_free().
5654 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5656 MONO_REQ_GC_UNSAFE_MODE;
5660 GError *gerror = NULL;
5662 mono_error_init (error);
5668 return g_strdup ("");
5670 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5672 mono_error_set_argument (error, "string", "%s", gerror->message);
5673 g_error_free (gerror);
5676 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5677 if (s->length > written) {
5678 /* allocate the total length and copy the part of the string that has been converted */
5679 char *as2 = (char *)g_malloc0 (s->length);
5680 memcpy (as2, as, written);
5689 * mono_string_to_utf8_ignore:
5692 * Converts a MonoString to its UTF8 representation. Will ignore
5693 * invalid surrogate pairs.
5694 * The resulting buffer should be freed with mono_free().
5698 mono_string_to_utf8_ignore (MonoString *s)
5700 MONO_REQ_GC_UNSAFE_MODE;
5709 return g_strdup ("");
5711 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5713 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5714 if (s->length > written) {
5715 /* allocate the total length and copy the part of the string that has been converted */
5716 char *as2 = (char *)g_malloc0 (s->length);
5717 memcpy (as2, as, written);
5726 * mono_string_to_utf8_image_ignore:
5727 * @s: a System.String
5729 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5732 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5734 MONO_REQ_GC_UNSAFE_MODE;
5736 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5740 * mono_string_to_utf8_mp_ignore:
5741 * @s: a System.String
5743 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5746 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5748 MONO_REQ_GC_UNSAFE_MODE;
5750 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5755 * mono_string_to_utf16:
5758 * Return an null-terminated array of the utf-16 chars
5759 * contained in @s. The result must be freed with g_free().
5760 * This is a temporary helper until our string implementation
5761 * is reworked to always include the null terminating char.
5764 mono_string_to_utf16 (MonoString *s)
5766 MONO_REQ_GC_UNSAFE_MODE;
5773 as = (char *)g_malloc ((s->length * 2) + 2);
5774 as [(s->length * 2)] = '\0';
5775 as [(s->length * 2) + 1] = '\0';
5778 return (gunichar2 *)(as);
5781 memcpy (as, mono_string_chars(s), s->length * 2);
5782 return (gunichar2 *)(as);
5786 * mono_string_to_utf32:
5789 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5790 * contained in @s. The result must be freed with g_free().
5793 mono_string_to_utf32 (MonoString *s)
5795 MONO_REQ_GC_UNSAFE_MODE;
5797 mono_unichar4 *utf32_output = NULL;
5798 GError *error = NULL;
5799 glong items_written;
5804 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5807 g_error_free (error);
5809 return utf32_output;
5813 * mono_string_from_utf16:
5814 * @data: the UTF16 string (LPWSTR) to convert
5816 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5818 * Returns: a MonoString.
5821 mono_string_from_utf16 (gunichar2 *data)
5823 MONO_REQ_GC_UNSAFE_MODE;
5825 MonoDomain *domain = mono_domain_get ();
5831 while (data [len]) len++;
5833 return mono_string_new_utf16 (domain, data, len);
5837 * mono_string_from_utf32:
5838 * @data: the UTF32 string (LPWSTR) to convert
5840 * Converts a UTF32 (UCS-4)to a MonoString.
5842 * Returns: a MonoString.
5845 mono_string_from_utf32 (mono_unichar4 *data)
5847 MONO_REQ_GC_UNSAFE_MODE;
5849 MonoString* result = NULL;
5850 mono_unichar2 *utf16_output = NULL;
5851 GError *error = NULL;
5852 glong items_written;
5858 while (data [len]) len++;
5860 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5863 g_error_free (error);
5865 result = mono_string_from_utf16 (utf16_output);
5866 g_free (utf16_output);
5871 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5873 MONO_REQ_GC_UNSAFE_MODE;
5880 r = mono_string_to_utf8_ignore (s);
5882 r = mono_string_to_utf8_checked (s, error);
5883 if (!mono_error_ok (error))
5890 len = strlen (r) + 1;
5892 mp_s = (char *)mono_mempool_alloc (mp, len);
5894 mp_s = (char *)mono_image_alloc (image, len);
5896 memcpy (mp_s, r, len);
5904 * mono_string_to_utf8_image:
5905 * @s: a System.String
5907 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5910 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5912 MONO_REQ_GC_UNSAFE_MODE;
5914 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5918 * mono_string_to_utf8_mp:
5919 * @s: a System.String
5921 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5924 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5926 MONO_REQ_GC_UNSAFE_MODE;
5928 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5932 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5935 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5937 eh_callbacks = *cbs;
5940 MonoRuntimeExceptionHandlingCallbacks *
5941 mono_get_eh_callbacks (void)
5943 return &eh_callbacks;
5947 * mono_raise_exception:
5948 * @ex: exception object
5950 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5953 mono_raise_exception (MonoException *ex)
5955 MONO_REQ_GC_UNSAFE_MODE;
5958 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5959 * that will cause gcc to omit the function epilog, causing problems when
5960 * the JIT tries to walk the stack, since the return address on the stack
5961 * will point into the next function in the executable, not this one.
5963 eh_callbacks.mono_raise_exception (ex);
5967 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5969 MONO_REQ_GC_UNSAFE_MODE;
5971 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5975 * mono_wait_handle_new:
5976 * @domain: Domain where the object will be created
5977 * @handle: Handle for the wait handle
5979 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5982 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5984 MONO_REQ_GC_UNSAFE_MODE;
5986 MonoWaitHandle *res;
5987 gpointer params [1];
5988 static MonoMethod *handle_set;
5990 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5992 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5994 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5996 params [0] = &handle;
5997 mono_runtime_invoke (handle_set, res, params, NULL);
6003 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6005 MONO_REQ_GC_UNSAFE_MODE;
6007 static MonoClassField *f_os_handle;
6008 static MonoClassField *f_safe_handle;
6010 if (!f_os_handle && !f_safe_handle) {
6011 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6012 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6017 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6021 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6028 mono_runtime_capture_context (MonoDomain *domain)
6030 MONO_REQ_GC_UNSAFE_MODE;
6032 RuntimeInvokeFunction runtime_invoke;
6034 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6035 MonoMethod *method = mono_get_context_capture_method ();
6036 MonoMethod *wrapper;
6039 wrapper = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
6040 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6041 domain->capture_context_method = mono_compile_method (method);
6044 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6046 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6049 * mono_async_result_new:
6050 * @domain:domain where the object will be created.
6051 * @handle: wait handle.
6052 * @state: state to pass to AsyncResult
6053 * @data: C closure data.
6055 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6056 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6060 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6062 MONO_REQ_GC_UNSAFE_MODE;
6064 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6065 MonoObject *context = mono_runtime_capture_context (domain);
6066 /* we must capture the execution context from the original thread */
6068 MONO_OBJECT_SETREF (res, execution_context, context);
6069 /* note: result may be null if the flow is suppressed */
6072 res->data = (void **)data;
6073 MONO_OBJECT_SETREF (res, object_data, object_data);
6074 MONO_OBJECT_SETREF (res, async_state, state);
6076 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6078 res->sync_completed = FALSE;
6079 res->completed = FALSE;
6085 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6087 MONO_REQ_GC_UNSAFE_MODE;
6093 g_assert (ares->async_delegate);
6095 ac = (MonoAsyncCall*) ares->object_data;
6097 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6099 gpointer wait_event = NULL;
6101 ac->msg->exc = NULL;
6102 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6103 MONO_OBJECT_SETREF (ac, res, res);
6105 mono_monitor_enter ((MonoObject*) ares);
6106 ares->completed = 1;
6108 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6109 mono_monitor_exit ((MonoObject*) ares);
6111 if (wait_event != NULL)
6112 SetEvent (wait_event);
6114 if (ac->cb_method) {
6115 /* we swallow the excepton as it is the behavior on .NET */
6116 MonoObject *exc = NULL;
6117 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6119 mono_unhandled_exception (exc);
6127 mono_message_init (MonoDomain *domain,
6128 MonoMethodMessage *this_obj,
6129 MonoReflectionMethod *method,
6130 MonoArray *out_args)
6132 MONO_REQ_GC_UNSAFE_MODE;
6134 static MonoClass *object_array_klass;
6135 static MonoClass *byte_array_klass;
6136 static MonoClass *string_array_klass;
6137 MonoMethodSignature *sig = mono_method_signature (method->method);
6143 if (!object_array_klass) {
6146 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6148 byte_array_klass = klass;
6150 klass = mono_array_class_get (mono_defaults.string_class, 1);
6152 string_array_klass = klass;
6154 klass = mono_array_class_get (mono_defaults.object_class, 1);
6157 mono_atomic_store_release (&object_array_klass, klass);
6160 MONO_OBJECT_SETREF (this_obj, method, method);
6162 MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6163 MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6164 this_obj->async_result = NULL;
6165 this_obj->call_type = CallType_Sync;
6167 names = g_new (char *, sig->param_count);
6168 mono_method_get_param_names (method->method, (const char **) names);
6169 MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6171 for (i = 0; i < sig->param_count; i++) {
6172 name = mono_string_new (domain, names [i]);
6173 mono_array_setref (this_obj->names, i, name);
6177 for (i = 0, j = 0; i < sig->param_count; i++) {
6178 if (sig->params [i]->byref) {
6180 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6181 mono_array_setref (this_obj->args, i, arg);
6185 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6189 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6192 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6196 #ifndef DISABLE_REMOTING
6198 * mono_remoting_invoke:
6199 * @real_proxy: pointer to a RealProxy object
6200 * @msg: The MonoMethodMessage to execute
6201 * @exc: used to store exceptions
6202 * @out_args: used to store output arguments
6204 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6205 * IMessage interface and it is not trivial to extract results from there. So
6206 * we call an helper method PrivateInvoke instead of calling
6207 * RealProxy::Invoke() directly.
6209 * Returns: the result object.
6212 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6213 MonoObject **exc, MonoArray **out_args)
6215 MONO_REQ_GC_UNSAFE_MODE;
6217 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6220 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6223 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6225 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6226 real_proxy->vtable->domain->private_invoke_method = im;
6229 pa [0] = real_proxy;
6234 return mono_runtime_invoke (im, NULL, pa, exc);
6239 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6240 MonoObject **exc, MonoArray **out_args)
6242 MONO_REQ_GC_UNSAFE_MODE;
6244 static MonoClass *object_array_klass;
6247 MonoMethodSignature *sig;
6249 int i, j, outarg_count = 0;
6251 #ifndef DISABLE_REMOTING
6252 if (target && mono_object_is_transparent_proxy (target)) {
6253 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6254 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6255 target = tp->rp->unwrapped_server;
6257 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6262 domain = mono_domain_get ();
6263 method = msg->method->method;
6264 sig = mono_method_signature (method);
6266 for (i = 0; i < sig->param_count; i++) {
6267 if (sig->params [i]->byref)
6271 if (!object_array_klass) {
6274 klass = mono_array_class_get (mono_defaults.object_class, 1);
6277 mono_memory_barrier ();
6278 object_array_klass = klass;
6281 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6284 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6286 for (i = 0, j = 0; i < sig->param_count; i++) {
6287 if (sig->params [i]->byref) {
6289 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6290 mono_array_setref (*out_args, j, arg);
6299 * mono_object_to_string:
6301 * @exc: Any exception thrown by ToString (). May be NULL.
6303 * Returns: the result of calling ToString () on an object.
6306 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6308 MONO_REQ_GC_UNSAFE_MODE;
6310 static MonoMethod *to_string = NULL;
6317 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6319 method = mono_object_get_virtual_method (obj, to_string);
6321 // Unbox value type if needed
6322 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6323 target = mono_object_unbox (obj);
6326 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6330 * mono_print_unhandled_exception:
6331 * @exc: The exception
6333 * Prints the unhandled exception.
6336 mono_print_unhandled_exception (MonoObject *exc)
6338 MONO_REQ_GC_UNSAFE_MODE;
6341 char *message = (char*)"";
6342 gboolean free_message = FALSE;
6345 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6346 message = g_strdup ("OutOfMemoryException");
6347 free_message = TRUE;
6348 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6349 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6350 free_message = TRUE;
6353 if (((MonoException*)exc)->native_trace_ips) {
6354 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6355 free_message = TRUE;
6357 MonoObject *other_exc = NULL;
6358 str = mono_object_to_string (exc, &other_exc);
6360 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6361 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6363 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6364 original_backtrace, nested_backtrace);
6366 g_free (original_backtrace);
6367 g_free (nested_backtrace);
6368 free_message = TRUE;
6370 message = mono_string_to_utf8_checked (str, &error);
6371 if (!mono_error_ok (&error)) {
6372 mono_error_cleanup (&error);
6373 message = (char *) "";
6375 free_message = TRUE;
6382 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6383 * exc->vtable->klass->name, message);
6385 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6392 * mono_delegate_ctor:
6393 * @this: pointer to an uninitialized delegate object
6394 * @target: target object
6395 * @addr: pointer to native code
6398 * Initialize a delegate and sets a specific method, not the one
6399 * associated with addr. This is useful when sharing generic code.
6400 * In that case addr will most probably not be associated with the
6401 * correct instantiation of the method.
6404 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6406 MONO_REQ_GC_UNSAFE_MODE;
6408 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6410 g_assert (this_obj);
6413 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6416 delegate->method = method;
6418 mono_stats.delegate_creations++;
6420 #ifndef DISABLE_REMOTING
6421 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6423 method = mono_marshal_get_remoting_invoke (method);
6424 delegate->method_ptr = mono_compile_method (method);
6425 MONO_OBJECT_SETREF (delegate, target, target);
6429 delegate->method_ptr = addr;
6430 MONO_OBJECT_SETREF (delegate, target, target);
6433 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6437 * mono_delegate_ctor:
6438 * @this: pointer to an uninitialized delegate object
6439 * @target: target object
6440 * @addr: pointer to native code
6442 * This is used to initialize a delegate.
6445 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6447 MONO_REQ_GC_UNSAFE_MODE;
6449 MonoDomain *domain = mono_domain_get ();
6451 MonoMethod *method = NULL;
6455 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6457 if (!ji && domain != mono_get_root_domain ())
6458 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6460 method = mono_jit_info_get_method (ji);
6461 g_assert (!method->klass->generic_container);
6464 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6468 * mono_method_call_message_new:
6469 * @method: method to encapsulate
6470 * @params: parameters to the method
6471 * @invoke: optional, delegate invoke.
6472 * @cb: async callback delegate.
6473 * @state: state passed to the async callback.
6475 * Translates arguments pointers into a MonoMethodMessage.
6478 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6479 MonoDelegate **cb, MonoObject **state)
6481 MONO_REQ_GC_UNSAFE_MODE;
6483 MonoDomain *domain = mono_domain_get ();
6484 MonoMethodSignature *sig = mono_method_signature (method);
6485 MonoMethodMessage *msg;
6488 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6491 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6492 count = sig->param_count - 2;
6494 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6495 count = sig->param_count;
6498 for (i = 0; i < count; i++) {
6503 if (sig->params [i]->byref)
6504 vpos = *((gpointer *)params [i]);
6508 klass = mono_class_from_mono_type (sig->params [i]);
6510 if (klass->valuetype)
6511 arg = mono_value_box (domain, klass, vpos);
6513 arg = *((MonoObject **)vpos);
6515 mono_array_setref (msg->args, i, arg);
6518 if (cb != NULL && state != NULL) {
6519 *cb = *((MonoDelegate **)params [i]);
6521 *state = *((MonoObject **)params [i]);
6528 * mono_method_return_message_restore:
6530 * Restore results from message based processing back to arguments pointers
6533 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6535 MONO_REQ_GC_UNSAFE_MODE;
6537 MonoMethodSignature *sig = mono_method_signature (method);
6538 int i, j, type, size, out_len;
6540 if (out_args == NULL)
6542 out_len = mono_array_length (out_args);
6546 for (i = 0, j = 0; i < sig->param_count; i++) {
6547 MonoType *pt = sig->params [i];
6552 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6554 arg = (char *)mono_array_get (out_args, gpointer, j);
6557 g_assert (type != MONO_TYPE_VOID);
6559 if (MONO_TYPE_IS_REFERENCE (pt)) {
6560 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6563 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6564 size = mono_class_value_size (klass, NULL);
6565 if (klass->has_references)
6566 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6568 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6570 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6571 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6580 #ifndef DISABLE_REMOTING
6583 * mono_load_remote_field:
6584 * @this: pointer to an object
6585 * @klass: klass of the object containing @field
6586 * @field: the field to load
6587 * @res: a storage to store the result
6589 * This method is called by the runtime on attempts to load fields of
6590 * transparent proxy objects. @this points to such TP, @klass is the class of
6591 * the object containing @field. @res is a storage location which can be
6592 * used to store the result.
6594 * Returns: an address pointing to the value of field.
6597 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6599 MONO_REQ_GC_UNSAFE_MODE;
6601 static MonoMethod *getter = NULL;
6602 MonoDomain *domain = mono_domain_get ();
6603 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6604 MonoClass *field_class;
6605 MonoMethodMessage *msg;
6606 MonoArray *out_args;
6610 g_assert (mono_object_is_transparent_proxy (this_obj));
6611 g_assert (res != NULL);
6613 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6614 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6619 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6621 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6624 field_class = mono_class_from_mono_type (field->type);
6626 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6627 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6628 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6630 full_name = mono_type_get_full_name (klass);
6631 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6632 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6635 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6637 if (exc) mono_raise_exception ((MonoException *)exc);
6639 if (mono_array_length (out_args) == 0)
6642 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6644 if (field_class->valuetype) {
6645 return ((char *)*res) + sizeof (MonoObject);
6651 * mono_load_remote_field_new:
6656 * Missing documentation.
6659 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6661 MONO_REQ_GC_UNSAFE_MODE;
6663 static MonoMethod *getter = NULL;
6664 MonoDomain *domain = mono_domain_get ();
6665 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6666 MonoClass *field_class;
6667 MonoMethodMessage *msg;
6668 MonoArray *out_args;
6669 MonoObject *exc, *res;
6672 g_assert (mono_object_is_transparent_proxy (this_obj));
6674 field_class = mono_class_from_mono_type (field->type);
6676 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6678 if (field_class->valuetype) {
6679 res = mono_object_new (domain, field_class);
6680 val = ((gchar *) res) + sizeof (MonoObject);
6684 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6689 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6691 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6694 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6695 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6697 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6699 full_name = mono_type_get_full_name (klass);
6700 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6701 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6704 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6706 if (exc) mono_raise_exception ((MonoException *)exc);
6708 if (mono_array_length (out_args) == 0)
6711 res = mono_array_get (out_args, MonoObject *, 0);
6717 * mono_store_remote_field:
6718 * @this_obj: pointer to an object
6719 * @klass: klass of the object containing @field
6720 * @field: the field to load
6721 * @val: the value/object to store
6723 * This method is called by the runtime on attempts to store fields of
6724 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6725 * the object containing @field. @val is the new value to store in @field.
6728 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6730 MONO_REQ_GC_UNSAFE_MODE;
6732 static MonoMethod *setter = NULL;
6733 MonoDomain *domain = mono_domain_get ();
6734 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6735 MonoClass *field_class;
6736 MonoMethodMessage *msg;
6737 MonoArray *out_args;
6742 g_assert (mono_object_is_transparent_proxy (this_obj));
6744 field_class = mono_class_from_mono_type (field->type);
6746 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6747 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6748 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6753 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6755 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6758 if (field_class->valuetype)
6759 arg = mono_value_box (domain, field_class, val);
6761 arg = *((MonoObject **)val);
6764 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6765 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6767 full_name = mono_type_get_full_name (klass);
6768 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6769 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6770 mono_array_setref (msg->args, 2, arg);
6773 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6775 if (exc) mono_raise_exception ((MonoException *)exc);
6779 * mono_store_remote_field_new:
6785 * Missing documentation
6788 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6790 MONO_REQ_GC_UNSAFE_MODE;
6792 static MonoMethod *setter = NULL;
6793 MonoDomain *domain = mono_domain_get ();
6794 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6795 MonoClass *field_class;
6796 MonoMethodMessage *msg;
6797 MonoArray *out_args;
6801 g_assert (mono_object_is_transparent_proxy (this_obj));
6803 field_class = mono_class_from_mono_type (field->type);
6805 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6806 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6807 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6812 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6814 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6817 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6818 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6820 full_name = mono_type_get_full_name (klass);
6821 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6822 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6823 mono_array_setref (msg->args, 2, arg);
6826 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6828 if (exc) mono_raise_exception ((MonoException *)exc);
6833 * mono_create_ftnptr:
6835 * Given a function address, create a function descriptor for it.
6836 * This is only needed on some platforms.
6839 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6841 return callbacks.create_ftnptr (domain, addr);
6845 * mono_get_addr_from_ftnptr:
6847 * Given a pointer to a function descriptor, return the function address.
6848 * This is only needed on some platforms.
6851 mono_get_addr_from_ftnptr (gpointer descr)
6853 return callbacks.get_addr_from_ftnptr (descr);
6857 * mono_string_chars:
6860 * Returns a pointer to the UCS16 characters stored in the MonoString
6863 mono_string_chars (MonoString *s)
6865 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
6871 * mono_string_length:
6874 * Returns the lenght in characters of the string
6877 mono_string_length (MonoString *s)
6879 MONO_REQ_GC_UNSAFE_MODE;
6885 * mono_array_length:
6886 * @array: a MonoArray*
6888 * Returns the total number of elements in the array. This works for
6889 * both vectors and multidimensional arrays.
6892 mono_array_length (MonoArray *array)
6894 MONO_REQ_GC_UNSAFE_MODE;
6896 return array->max_length;
6900 * mono_array_addr_with_size:
6901 * @array: a MonoArray*
6902 * @size: size of the array elements
6903 * @idx: index into the array
6905 * Returns the address of the @idx element in the array.
6908 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6910 MONO_REQ_GC_UNSAFE_MODE;
6912 return ((char*)(array)->vector) + size * idx;
6917 mono_glist_to_array (GList *list, MonoClass *eclass)
6919 MonoDomain *domain = mono_domain_get ();
6926 len = g_list_length (list);
6927 res = mono_array_new (domain, eclass, len);
6929 for (i = 0; list; list = list->next, i++)
6930 mono_array_set (res, gpointer, i, list->data);