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_mutex_lock (&ldstr_section)
63 #define ldstr_unlock() mono_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 = 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 mono_mutex_t initialization_section;
112 } TypeInitializationLock;
114 /* for locking access to type_initialization_hash and blocked_thread_hash */
115 static mono_mutex_t 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_PREPARE_BLOCKING;
122 mono_mutex_lock (&type_initialization_section);
123 MONO_FINISH_BLOCKING;
127 mono_type_initialization_unlock (void)
129 mono_mutex_unlock (&type_initialization_section);
133 mono_type_init_lock (TypeInitializationLock *lock)
135 MONO_REQ_GC_NEUTRAL_MODE;
138 mono_mutex_lock (&lock->initialization_section);
139 MONO_FINISH_TRY_BLOCKING;
143 mono_type_init_unlock (TypeInitializationLock *lock)
145 mono_mutex_unlock (&lock->initialization_section);
148 /* from vtable to lock */
149 static GHashTable *type_initialization_hash;
151 /* from thread id to thread id being waited on */
152 static GHashTable *blocked_thread_hash;
155 static MonoThread *main_thread;
157 /* Functions supplied by the runtime */
158 static MonoRuntimeCallbacks callbacks;
161 * mono_thread_set_main:
162 * @thread: thread to set as the main thread
164 * This function can be used to instruct the runtime to treat @thread
165 * as the main thread, ie, the thread that would normally execute the Main()
166 * method. This basically means that at the end of @thread, the runtime will
167 * wait for the existing foreground threads to quit and other such details.
170 mono_thread_set_main (MonoThread *thread)
172 MONO_REQ_GC_UNSAFE_MODE;
174 static gboolean registered = FALSE;
177 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
181 main_thread = thread;
185 mono_thread_get_main (void)
187 MONO_REQ_GC_UNSAFE_MODE;
193 mono_type_initialization_init (void)
195 mono_mutex_init_recursive (&type_initialization_section);
196 type_initialization_hash = g_hash_table_new (NULL, NULL);
197 blocked_thread_hash = g_hash_table_new (NULL, NULL);
198 mono_mutex_init_recursive (&ldstr_section);
202 mono_type_initialization_cleanup (void)
205 /* This is causing race conditions with
206 * mono_release_type_locks
208 mono_mutex_destroy (&type_initialization_section);
209 g_hash_table_destroy (type_initialization_hash);
210 type_initialization_hash = NULL;
212 mono_mutex_destroy (&ldstr_section);
213 g_hash_table_destroy (blocked_thread_hash);
214 blocked_thread_hash = NULL;
220 * get_type_init_exception_for_vtable:
222 * Return the stored type initialization exception for VTABLE.
224 static MonoException*
225 get_type_init_exception_for_vtable (MonoVTable *vtable)
227 MONO_REQ_GC_UNSAFE_MODE;
229 MonoDomain *domain = vtable->domain;
230 MonoClass *klass = vtable->klass;
234 if (!vtable->init_failed)
235 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
238 * If the initializing thread was rudely aborted, the exception is not stored
242 mono_domain_lock (domain);
243 if (domain->type_init_exception_hash)
244 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
245 mono_domain_unlock (domain);
248 if (klass->name_space && *klass->name_space)
249 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
251 full_name = g_strdup (klass->name);
252 ex = mono_get_exception_type_initialization (full_name, NULL);
259 * mono_runtime_class_init:
260 * @vtable: vtable that needs to be initialized
262 * This routine calls the class constructor for @vtable.
265 mono_runtime_class_init (MonoVTable *vtable)
267 MONO_REQ_GC_UNSAFE_MODE;
269 mono_runtime_class_init_full (vtable, TRUE);
273 * mono_runtime_class_init_full:
274 * @vtable that neeeds to be initialized
275 * @raise_exception is TRUE, exceptions are raised intead of returned
279 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
281 MONO_REQ_GC_UNSAFE_MODE;
284 MonoException *exc_to_throw;
285 MonoMethod *method = NULL;
288 MonoDomain *domain = vtable->domain;
289 TypeInitializationLock *lock;
290 MonoNativeThreadId tid;
291 int do_initialization = 0;
292 MonoDomain *last_domain = NULL;
294 if (vtable->initialized)
298 klass = vtable->klass;
300 if (!klass->image->checked_module_cctor) {
301 mono_image_check_for_module_cctor (klass->image);
302 if (klass->image->has_module_cctor) {
304 MonoClass *module_klass;
305 MonoVTable *module_vtable;
307 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
309 exc = mono_error_convert_to_exception (&error);
311 mono_raise_exception (exc);
315 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
318 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
323 method = mono_class_get_cctor (klass);
325 vtable->initialized = 1;
329 tid = mono_native_thread_id_get ();
331 mono_type_initialization_lock ();
332 /* double check... */
333 if (vtable->initialized) {
334 mono_type_initialization_unlock ();
337 if (vtable->init_failed) {
338 mono_type_initialization_unlock ();
340 /* The type initialization already failed once, rethrow the same exception */
342 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
343 return get_type_init_exception_for_vtable (vtable);
345 lock = g_hash_table_lookup (type_initialization_hash, vtable);
347 /* This thread will get to do the initialization */
348 if (mono_domain_get () != domain) {
349 /* Transfer into the target domain */
350 last_domain = mono_domain_get ();
351 if (!mono_domain_set (domain, FALSE)) {
352 vtable->initialized = 1;
353 mono_type_initialization_unlock ();
355 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
356 return mono_get_exception_appdomain_unloaded ();
359 lock = g_malloc (sizeof(TypeInitializationLock));
360 mono_mutex_init_recursive (&lock->initialization_section);
361 lock->initializing_tid = tid;
362 lock->waiting_count = 1;
364 /* grab the vtable lock while this thread still owns type_initialization_section */
365 /* This is why type_initialization_lock needs to enter blocking mode */
366 mono_type_init_lock (lock);
367 g_hash_table_insert (type_initialization_hash, vtable, lock);
368 do_initialization = 1;
371 TypeInitializationLock *pending_lock;
373 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
374 mono_type_initialization_unlock ();
377 /* see if the thread doing the initialization is already blocked on this thread */
378 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
379 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
380 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
381 if (!pending_lock->done) {
382 mono_type_initialization_unlock ();
385 /* the thread doing the initialization is blocked on this thread,
386 but on a lock that has already been freed. It just hasn't got
391 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
393 ++lock->waiting_count;
394 /* record the fact that we are waiting on the initializing thread */
395 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
397 mono_type_initialization_unlock ();
399 if (do_initialization) {
400 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
402 /* If the initialization failed, mark the class as unusable. */
403 /* Avoid infinite loops */
405 (klass->image == mono_defaults.corlib &&
406 !strcmp (klass->name_space, "System") &&
407 !strcmp (klass->name, "TypeInitializationException")))) {
408 vtable->init_failed = 1;
410 if (klass->name_space && *klass->name_space)
411 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
413 full_name = g_strdup (klass->name);
414 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
418 * Store the exception object so it could be thrown on subsequent
421 mono_domain_lock (domain);
422 if (!domain->type_init_exception_hash)
423 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");
424 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
425 mono_domain_unlock (domain);
429 mono_domain_set (last_domain, TRUE);
431 mono_type_init_unlock (lock);
433 /* this just blocks until the initializing thread is done */
434 mono_type_init_lock (lock);
435 mono_type_init_unlock (lock);
438 mono_type_initialization_lock ();
439 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
440 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
441 --lock->waiting_count;
442 if (lock->waiting_count == 0) {
443 mono_mutex_destroy (&lock->initialization_section);
444 g_hash_table_remove (type_initialization_hash, vtable);
447 mono_memory_barrier ();
448 if (!vtable->init_failed)
449 vtable->initialized = 1;
450 mono_type_initialization_unlock ();
452 if (vtable->init_failed) {
453 /* Either we were the initializing thread or we waited for the initialization */
455 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
456 return get_type_init_exception_for_vtable (vtable);
462 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
464 MONO_REQ_GC_NEUTRAL_MODE;
466 MonoVTable *vtable = (MonoVTable*)key;
468 TypeInitializationLock *lock = (TypeInitializationLock*) value;
469 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
472 * Have to set this since it cannot be set by the normal code in
473 * mono_runtime_class_init (). In this case, the exception object is not stored,
474 * and get_type_init_exception_for_class () needs to be aware of this.
476 vtable->init_failed = 1;
477 mono_type_init_unlock (lock);
478 --lock->waiting_count;
479 if (lock->waiting_count == 0) {
480 mono_mutex_destroy (&lock->initialization_section);
489 mono_release_type_locks (MonoInternalThread *thread)
491 MONO_REQ_GC_UNSAFE_MODE;
493 mono_type_initialization_lock ();
494 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
495 mono_type_initialization_unlock ();
499 default_trampoline (MonoMethod *method)
505 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
507 g_assert_not_reached ();
512 #ifndef DISABLE_REMOTING
515 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
517 g_error ("remoting not installed");
521 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
525 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
527 g_assert_not_reached ();
531 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
532 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
533 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
534 static MonoImtThunkBuilder imt_thunk_builder;
535 #if (MONO_IMT_SIZE > 32)
536 #error "MONO_IMT_SIZE cannot be larger than 32"
540 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
542 memcpy (&callbacks, cbs, sizeof (*cbs));
545 MonoRuntimeCallbacks*
546 mono_get_runtime_callbacks (void)
552 mono_install_trampoline (MonoTrampoline func)
554 arch_create_jit_trampoline = func? func: default_trampoline;
558 mono_install_jump_trampoline (MonoJumpTrampoline func)
560 arch_create_jump_trampoline = func? func: default_jump_trampoline;
563 #ifndef DISABLE_REMOTING
565 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
567 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
572 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
574 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
578 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
579 imt_thunk_builder = func;
582 static MonoCompileFunc default_mono_compile_method = NULL;
585 * mono_install_compile_method:
586 * @func: function to install
588 * This is a VM internal routine
591 mono_install_compile_method (MonoCompileFunc func)
593 default_mono_compile_method = func;
597 * mono_compile_method:
598 * @method: The method to compile.
600 * This JIT-compiles the method, and returns the pointer to the native code
604 mono_compile_method (MonoMethod *method)
606 MONO_REQ_GC_NEUTRAL_MODE
608 if (!default_mono_compile_method) {
609 g_error ("compile method called on uninitialized runtime");
612 return default_mono_compile_method (method);
616 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
618 MONO_REQ_GC_NEUTRAL_MODE
620 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
624 mono_runtime_create_delegate_trampoline (MonoClass *klass)
626 MONO_REQ_GC_NEUTRAL_MODE
628 return arch_create_delegate_trampoline (mono_domain_get (), klass);
631 static MonoFreeMethodFunc default_mono_free_method = NULL;
634 * mono_install_free_method:
635 * @func: pointer to the MonoFreeMethodFunc used to release a method
637 * This is an internal VM routine, it is used for the engines to
638 * register a handler to release the resources associated with a method.
640 * Methods are freed when no more references to the delegate that holds
644 mono_install_free_method (MonoFreeMethodFunc func)
646 default_mono_free_method = func;
650 * mono_runtime_free_method:
651 * @domain; domain where the method is hosted
652 * @method: method to release
654 * This routine is invoked to free the resources associated with
655 * a method that has been JIT compiled. This is used to discard
656 * methods that were used only temporarily (for example, used in marshalling)
660 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
662 MONO_REQ_GC_NEUTRAL_MODE
664 if (default_mono_free_method != NULL)
665 default_mono_free_method (domain, method);
667 mono_method_clear_object (domain, method);
669 mono_free_method (method);
673 * The vtables in the root appdomain are assumed to be reachable by other
674 * roots, and we don't use typed allocation in the other domains.
677 /* The sync block is no longer a GC pointer */
678 #define GC_HEADER_BITMAP (0)
680 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
683 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
685 MONO_REQ_GC_NEUTRAL_MODE;
687 MonoClassField *field;
693 max_size = mono_class_data_size (klass) / sizeof (gpointer);
695 max_size = klass->instance_size / sizeof (gpointer);
696 if (max_size > size) {
697 g_assert (offset <= 0);
698 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
703 /*An Ephemeron cannot be marked by sgen*/
704 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
706 memset (bitmap, 0, size / 8);
711 for (p = klass; p != NULL; p = p->parent) {
712 gpointer iter = NULL;
713 while ((field = mono_class_get_fields (p, &iter))) {
717 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
719 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
722 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
725 /* FIXME: should not happen, flag as type load error */
726 if (field->type->byref)
729 if (static_fields && field->offset == -1)
733 pos = field->offset / sizeof (gpointer);
736 type = mono_type_get_underlying_type (field->type);
737 switch (type->type) {
740 case MONO_TYPE_FNPTR:
742 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
747 if (klass->image != mono_defaults.corlib)
750 case MONO_TYPE_STRING:
751 case MONO_TYPE_SZARRAY:
752 case MONO_TYPE_CLASS:
753 case MONO_TYPE_OBJECT:
754 case MONO_TYPE_ARRAY:
755 g_assert ((field->offset % sizeof(gpointer)) == 0);
757 g_assert (pos < size || pos <= max_size);
758 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
759 *max_set = MAX (*max_set, pos);
761 case MONO_TYPE_GENERICINST:
762 if (!mono_type_generic_inst_is_valuetype (type)) {
763 g_assert ((field->offset % sizeof(gpointer)) == 0);
765 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
766 *max_set = MAX (*max_set, pos);
771 case MONO_TYPE_VALUETYPE: {
772 MonoClass *fclass = mono_class_from_mono_type (field->type);
773 if (fclass->has_references) {
774 /* remove the object header */
775 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
789 case MONO_TYPE_BOOLEAN:
793 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
804 * mono_class_compute_bitmap:
806 * Mono internal function to compute a bitmap of reference fields in a class.
809 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
811 MONO_REQ_GC_NEUTRAL_MODE;
813 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
818 * similar to the above, but sets the bits in the bitmap for any non-ref field
819 * and ignores static fields
822 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
824 MonoClassField *field;
829 max_size = class->instance_size / sizeof (gpointer);
830 if (max_size >= size) {
831 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
834 for (p = class; p != NULL; p = p->parent) {
835 gpointer iter = NULL;
836 while ((field = mono_class_get_fields (p, &iter))) {
839 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
841 /* FIXME: should not happen, flag as type load error */
842 if (field->type->byref)
845 pos = field->offset / sizeof (gpointer);
848 type = mono_type_get_underlying_type (field->type);
849 switch (type->type) {
850 #if SIZEOF_VOID_P == 8
854 case MONO_TYPE_FNPTR:
859 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
860 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
861 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
864 #if SIZEOF_VOID_P == 4
868 case MONO_TYPE_FNPTR:
873 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
874 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
875 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
881 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
882 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
883 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
886 case MONO_TYPE_BOOLEAN:
889 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
891 case MONO_TYPE_STRING:
892 case MONO_TYPE_SZARRAY:
893 case MONO_TYPE_CLASS:
894 case MONO_TYPE_OBJECT:
895 case MONO_TYPE_ARRAY:
897 case MONO_TYPE_GENERICINST:
898 if (!mono_type_generic_inst_is_valuetype (type)) {
903 case MONO_TYPE_VALUETYPE: {
904 MonoClass *fclass = mono_class_from_mono_type (field->type);
905 /* remove the object header */
906 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
910 g_assert_not_reached ();
919 * mono_class_insecure_overlapping:
920 * check if a class with explicit layout has references and non-references
921 * fields overlapping.
923 * Returns: TRUE if it is insecure to load the type.
926 mono_class_insecure_overlapping (MonoClass *klass)
930 gsize default_bitmap [4] = {0};
932 gsize default_nrbitmap [4] = {0};
933 int i, insecure = FALSE;
936 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
937 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
939 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
940 int idx = i % (sizeof (bitmap [0]) * 8);
941 if (bitmap [idx] & nrbitmap [idx]) {
946 if (bitmap != default_bitmap)
948 if (nrbitmap != default_nrbitmap)
951 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
959 mono_string_alloc (int length)
961 MONO_REQ_GC_UNSAFE_MODE;
962 return mono_string_new_size (mono_domain_get (), length);
966 mono_class_compute_gc_descriptor (MonoClass *klass)
968 MONO_REQ_GC_NEUTRAL_MODE;
972 gsize default_bitmap [4] = {0};
973 static gboolean gcj_inited = FALSE;
978 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
979 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
982 mono_loader_unlock ();
986 mono_class_init (klass);
988 if (klass->gc_descr_inited)
991 klass->gc_descr_inited = TRUE;
992 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
994 bitmap = default_bitmap;
995 if (klass == mono_defaults.string_class) {
996 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
997 } else if (klass->rank) {
998 mono_class_compute_gc_descriptor (klass->element_class);
999 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1001 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1002 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1003 class->name_space, class->name);*/
1005 /* remove the object header */
1006 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1007 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));
1008 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1009 class->name_space, class->name);*/
1010 if (bitmap != default_bitmap)
1014 /*static int count = 0;
1017 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1018 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1020 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1021 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1023 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1024 if (bitmap != default_bitmap)
1030 * field_is_special_static:
1031 * @fklass: The MonoClass to look up.
1032 * @field: The MonoClassField describing the field.
1034 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1035 * SPECIAL_STATIC_NONE otherwise.
1038 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1040 MONO_REQ_GC_NEUTRAL_MODE;
1042 MonoCustomAttrInfo *ainfo;
1044 ainfo = mono_custom_attrs_from_field (fklass, field);
1047 for (i = 0; i < ainfo->num_attrs; ++i) {
1048 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1049 if (klass->image == mono_defaults.corlib) {
1050 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1051 mono_custom_attrs_free (ainfo);
1052 return SPECIAL_STATIC_THREAD;
1054 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1055 mono_custom_attrs_free (ainfo);
1056 return SPECIAL_STATIC_CONTEXT;
1060 mono_custom_attrs_free (ainfo);
1061 return SPECIAL_STATIC_NONE;
1064 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1065 #define mix(a,b,c) { \
1066 a -= c; a ^= rot(c, 4); c += b; \
1067 b -= a; b ^= rot(a, 6); a += c; \
1068 c -= b; c ^= rot(b, 8); b += a; \
1069 a -= c; a ^= rot(c,16); c += b; \
1070 b -= a; b ^= rot(a,19); a += c; \
1071 c -= b; c ^= rot(b, 4); b += a; \
1073 #define final(a,b,c) { \
1074 c ^= b; c -= rot(b,14); \
1075 a ^= c; a -= rot(c,11); \
1076 b ^= a; b -= rot(a,25); \
1077 c ^= b; c -= rot(b,16); \
1078 a ^= c; a -= rot(c,4); \
1079 b ^= a; b -= rot(a,14); \
1080 c ^= b; c -= rot(b,24); \
1084 * mono_method_get_imt_slot:
1086 * The IMT slot is embedded into AOTed code, so this must return the same value
1087 * for the same method across all executions. This means:
1088 * - pointers shouldn't be used as hash values.
1089 * - mono_metadata_str_hash () should be used for hashing strings.
1092 mono_method_get_imt_slot (MonoMethod *method)
1094 MONO_REQ_GC_NEUTRAL_MODE;
1096 MonoMethodSignature *sig;
1098 guint32 *hashes_start, *hashes;
1102 /* This can be used to stress tests the collision code */
1106 * We do this to simplify generic sharing. It will hurt
1107 * performance in cases where a class implements two different
1108 * instantiations of the same generic interface.
1109 * The code in build_imt_slots () depends on this.
1111 if (method->is_inflated)
1112 method = ((MonoMethodInflated*)method)->declaring;
1114 sig = mono_method_signature (method);
1115 hashes_count = sig->param_count + 4;
1116 hashes_start = malloc (hashes_count * sizeof (guint32));
1117 hashes = hashes_start;
1119 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1120 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1121 method->klass->name_space, method->klass->name, method->name);
1124 /* Initialize hashes */
1125 hashes [0] = mono_metadata_str_hash (method->klass->name);
1126 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1127 hashes [2] = mono_metadata_str_hash (method->name);
1128 hashes [3] = mono_metadata_type_hash (sig->ret);
1129 for (i = 0; i < sig->param_count; i++) {
1130 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1133 /* Setup internal state */
1134 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1136 /* Handle most of the hashes */
1137 while (hashes_count > 3) {
1146 /* Handle the last 3 hashes (all the case statements fall through) */
1147 switch (hashes_count) {
1148 case 3 : c += hashes [2];
1149 case 2 : b += hashes [1];
1150 case 1 : a += hashes [0];
1152 case 0: /* nothing left to add */
1156 free (hashes_start);
1157 /* Report the result */
1158 return c % MONO_IMT_SIZE;
1167 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1168 MONO_REQ_GC_NEUTRAL_MODE;
1170 guint32 imt_slot = mono_method_get_imt_slot (method);
1171 MonoImtBuilderEntry *entry;
1173 if (slot_num >= 0 && imt_slot != slot_num) {
1174 /* we build just a single imt slot and this is not it */
1178 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1179 entry->key = method;
1180 entry->value.vtable_slot = vtable_slot;
1181 entry->next = imt_builder [imt_slot];
1182 if (imt_builder [imt_slot] != NULL) {
1183 entry->children = imt_builder [imt_slot]->children + 1;
1184 if (entry->children == 1) {
1185 mono_stats.imt_slots_with_collisions++;
1186 *imt_collisions_bitmap |= (1 << imt_slot);
1189 entry->children = 0;
1190 mono_stats.imt_used_slots++;
1192 imt_builder [imt_slot] = entry;
1195 char *method_name = mono_method_full_name (method, TRUE);
1196 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1197 method, method_name, imt_slot, vtable_slot, entry->children);
1198 g_free (method_name);
1205 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1207 MonoMethod *method = e->key;
1208 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1212 method->klass->name_space,
1213 method->klass->name,
1216 printf (" * %s: NULL\n", message);
1222 compare_imt_builder_entries (const void *p1, const void *p2) {
1223 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1224 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1226 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1230 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1232 MONO_REQ_GC_NEUTRAL_MODE;
1234 int count = end - start;
1235 int chunk_start = out_array->len;
1238 for (i = start; i < end; ++i) {
1239 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1240 item->key = sorted_array [i]->key;
1241 item->value = sorted_array [i]->value;
1242 item->has_target_code = sorted_array [i]->has_target_code;
1243 item->is_equals = TRUE;
1245 item->check_target_idx = out_array->len + 1;
1247 item->check_target_idx = 0;
1248 g_ptr_array_add (out_array, item);
1251 int middle = start + count / 2;
1252 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1254 item->key = sorted_array [middle]->key;
1255 item->is_equals = FALSE;
1256 g_ptr_array_add (out_array, item);
1257 imt_emit_ir (sorted_array, start, middle, out_array);
1258 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1264 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1265 MONO_REQ_GC_NEUTRAL_MODE;
1267 int number_of_entries = entries->children + 1;
1268 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1269 GPtrArray *result = g_ptr_array_new ();
1270 MonoImtBuilderEntry *current_entry;
1273 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1274 sorted_array [i] = current_entry;
1276 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1278 /*for (i = 0; i < number_of_entries; i++) {
1279 print_imt_entry (" sorted array:", sorted_array [i], i);
1282 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1284 free (sorted_array);
1289 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1291 MONO_REQ_GC_NEUTRAL_MODE;
1293 if (imt_builder_entry != NULL) {
1294 if (imt_builder_entry->children == 0 && !fail_tramp) {
1295 /* No collision, return the vtable slot contents */
1296 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1298 /* Collision, build the thunk */
1299 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1302 result = imt_thunk_builder (vtable, domain,
1303 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1304 for (i = 0; i < imt_ir->len; ++i)
1305 g_free (g_ptr_array_index (imt_ir, i));
1306 g_ptr_array_free (imt_ir, TRUE);
1318 static MonoImtBuilderEntry*
1319 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1322 * LOCKING: requires the loader and domain locks.
1326 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1328 MONO_REQ_GC_NEUTRAL_MODE;
1332 guint32 imt_collisions_bitmap = 0;
1333 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1334 int method_count = 0;
1335 gboolean record_method_count_for_max_collisions = FALSE;
1336 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1339 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1341 for (i = 0; i < klass->interface_offsets_count; ++i) {
1342 MonoClass *iface = klass->interfaces_packed [i];
1343 int interface_offset = klass->interface_offsets_packed [i];
1344 int method_slot_in_interface, vt_slot;
1346 if (mono_class_has_variant_generic_params (iface))
1347 has_variant_iface = TRUE;
1349 mono_class_setup_methods (iface);
1350 vt_slot = interface_offset;
1351 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1354 if (slot_num >= 0 && iface->is_inflated) {
1356 * The imt slot of the method is the same as for its declaring method,
1357 * see the comment in mono_method_get_imt_slot (), so we can
1358 * avoid inflating methods which will be discarded by
1359 * add_imt_builder_entry anyway.
1361 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1362 if (mono_method_get_imt_slot (method) != slot_num) {
1367 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1368 if (method->is_generic) {
1369 has_generic_virtual = TRUE;
1374 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1375 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1380 if (extra_interfaces) {
1381 int interface_offset = klass->vtable_size;
1383 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1384 MonoClass* iface = list_item->data;
1385 int method_slot_in_interface;
1386 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1387 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1389 if (method->is_generic)
1390 has_generic_virtual = TRUE;
1391 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1393 interface_offset += iface->method.count;
1396 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1397 /* overwrite the imt slot only if we're building all the entries or if
1398 * we're building this specific one
1400 if (slot_num < 0 || i == slot_num) {
1401 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1404 if (imt_builder [i]) {
1405 MonoImtBuilderEntry *entry;
1407 /* Link entries with imt_builder [i] */
1408 for (entry = entries; entry->next; entry = entry->next) {
1410 MonoMethod *method = (MonoMethod*)entry->key;
1411 char *method_name = mono_method_full_name (method, TRUE);
1412 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1413 g_free (method_name);
1416 entry->next = imt_builder [i];
1417 entries->children += imt_builder [i]->children + 1;
1419 imt_builder [i] = entries;
1422 if (has_generic_virtual || has_variant_iface) {
1424 * There might be collisions later when the the thunk is expanded.
1426 imt_collisions_bitmap |= (1 << i);
1429 * The IMT thunk might be called with an instance of one of the
1430 * generic virtual methods, so has to fallback to the IMT trampoline.
1432 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (i));
1434 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1437 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1441 if (imt_builder [i] != NULL) {
1442 int methods_in_slot = imt_builder [i]->children + 1;
1443 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1444 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1445 record_method_count_for_max_collisions = TRUE;
1447 method_count += methods_in_slot;
1451 mono_stats.imt_number_of_methods += method_count;
1452 if (record_method_count_for_max_collisions) {
1453 mono_stats.imt_method_count_when_max_collisions = method_count;
1456 for (i = 0; i < MONO_IMT_SIZE; i++) {
1457 MonoImtBuilderEntry* entry = imt_builder [i];
1458 while (entry != NULL) {
1459 MonoImtBuilderEntry* next = entry->next;
1465 /* we OR the bitmap since we may build just a single imt slot at a time */
1466 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1470 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1471 MONO_REQ_GC_NEUTRAL_MODE;
1473 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1477 * mono_vtable_build_imt_slot:
1478 * @vtable: virtual object table struct
1479 * @imt_slot: slot in the IMT table
1481 * Fill the given @imt_slot in the IMT table of @vtable with
1482 * a trampoline or a thunk for the case of collisions.
1483 * This is part of the internal mono API.
1485 * LOCKING: Take the domain lock.
1488 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1490 MONO_REQ_GC_NEUTRAL_MODE;
1492 gpointer *imt = (gpointer*)vtable;
1493 imt -= MONO_IMT_SIZE;
1494 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1496 /* no support for extra interfaces: the proxy objects will need
1497 * to build the complete IMT
1498 * Update and heck needs to ahppen inside the proper domain lock, as all
1499 * the changes made to a MonoVTable.
1501 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1502 mono_domain_lock (vtable->domain);
1503 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1504 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1505 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1506 mono_domain_unlock (vtable->domain);
1507 mono_loader_unlock ();
1512 * The first two free list entries both belong to the wait list: The
1513 * first entry is the pointer to the head of the list and the second
1514 * entry points to the last element. That way appending and removing
1515 * the first element are both O(1) operations.
1517 #ifdef MONO_SMALL_CONFIG
1518 #define NUM_FREE_LISTS 6
1520 #define NUM_FREE_LISTS 12
1522 #define FIRST_FREE_LIST_SIZE 64
1523 #define MAX_WAIT_LENGTH 50
1524 #define THUNK_THRESHOLD 10
1527 * LOCKING: The domain lock must be held.
1530 init_thunk_free_lists (MonoDomain *domain)
1532 MONO_REQ_GC_NEUTRAL_MODE;
1534 if (domain->thunk_free_lists)
1536 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1540 list_index_for_size (int item_size)
1543 int size = FIRST_FREE_LIST_SIZE;
1545 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1554 * mono_method_alloc_generic_virtual_thunk:
1556 * @size: size in bytes
1558 * Allocs size bytes to be used for the code of a generic virtual
1559 * thunk. It's either allocated from the domain's code manager or
1560 * reused from a previously invalidated piece.
1562 * LOCKING: The domain lock must be held.
1565 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1567 MONO_REQ_GC_NEUTRAL_MODE;
1569 static gboolean inited = FALSE;
1570 static int generic_virtual_thunks_size = 0;
1574 MonoThunkFreeList **l;
1576 init_thunk_free_lists (domain);
1578 size += sizeof (guint32);
1579 if (size < sizeof (MonoThunkFreeList))
1580 size = sizeof (MonoThunkFreeList);
1582 i = list_index_for_size (size);
1583 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1584 if ((*l)->size >= size) {
1585 MonoThunkFreeList *item = *l;
1587 return ((guint32*)item) + 1;
1591 /* no suitable item found - search lists of larger sizes */
1592 while (++i < NUM_FREE_LISTS) {
1593 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1596 g_assert (item->size > size);
1597 domain->thunk_free_lists [i] = item->next;
1598 return ((guint32*)item) + 1;
1601 /* still nothing found - allocate it */
1603 mono_counters_register ("Generic virtual thunk bytes",
1604 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1607 generic_virtual_thunks_size += size;
1609 p = mono_domain_code_reserve (domain, size);
1612 mono_domain_lock (domain);
1613 if (!domain->generic_virtual_thunks)
1614 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1615 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1616 mono_domain_unlock (domain);
1622 * LOCKING: The domain lock must be held.
1625 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1627 MONO_REQ_GC_NEUTRAL_MODE;
1630 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1631 gboolean found = FALSE;
1633 mono_domain_lock (domain);
1634 if (!domain->generic_virtual_thunks)
1635 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1636 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1638 mono_domain_unlock (domain);
1641 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1643 init_thunk_free_lists (domain);
1645 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1646 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1647 int length = item->length;
1650 /* unlink the first item from the wait list */
1651 domain->thunk_free_lists [0] = item->next;
1652 domain->thunk_free_lists [0]->length = length - 1;
1654 i = list_index_for_size (item->size);
1656 /* put it in the free list */
1657 item->next = domain->thunk_free_lists [i];
1658 domain->thunk_free_lists [i] = item;
1662 if (domain->thunk_free_lists [1]) {
1663 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1664 domain->thunk_free_lists [0]->length++;
1666 g_assert (!domain->thunk_free_lists [0]);
1668 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1669 domain->thunk_free_lists [0]->length = 1;
1673 typedef struct _GenericVirtualCase {
1677 struct _GenericVirtualCase *next;
1678 } GenericVirtualCase;
1681 * get_generic_virtual_entries:
1683 * Return IMT entries for the generic virtual method instances and
1684 * variant interface methods for vtable slot
1687 static MonoImtBuilderEntry*
1688 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1690 MONO_REQ_GC_NEUTRAL_MODE;
1692 GenericVirtualCase *list;
1693 MonoImtBuilderEntry *entries;
1695 mono_domain_lock (domain);
1696 if (!domain->generic_virtual_cases)
1697 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1699 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1702 for (; list; list = list->next) {
1703 MonoImtBuilderEntry *entry;
1705 if (list->count < THUNK_THRESHOLD)
1708 entry = g_new0 (MonoImtBuilderEntry, 1);
1709 entry->key = list->method;
1710 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1711 entry->has_target_code = 1;
1713 entry->children = entries->children + 1;
1714 entry->next = entries;
1718 mono_domain_unlock (domain);
1720 /* FIXME: Leaking memory ? */
1725 * mono_method_add_generic_virtual_invocation:
1727 * @vtable_slot: pointer to the vtable slot
1728 * @method: the inflated generic virtual method
1729 * @code: the method's code
1731 * Registers a call via unmanaged code to a generic virtual method
1732 * instantiation or variant interface method. If the number of calls reaches a threshold
1733 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1734 * virtual method thunk.
1737 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1738 gpointer *vtable_slot,
1739 MonoMethod *method, gpointer code)
1741 MONO_REQ_GC_NEUTRAL_MODE;
1743 static gboolean inited = FALSE;
1744 static int num_added = 0;
1746 GenericVirtualCase *gvc, *list;
1747 MonoImtBuilderEntry *entries;
1751 mono_domain_lock (domain);
1752 if (!domain->generic_virtual_cases)
1753 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1755 /* Check whether the case was already added */
1756 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1759 if (gvc->method == method)
1764 /* If not found, make a new one */
1766 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1767 gvc->method = method;
1770 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1772 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1775 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1781 if (++gvc->count == THUNK_THRESHOLD) {
1782 gpointer *old_thunk = *vtable_slot;
1783 gpointer vtable_trampoline = NULL;
1784 gpointer imt_trampoline = NULL;
1786 if ((gpointer)vtable_slot < (gpointer)vtable) {
1787 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1788 int imt_slot = MONO_IMT_SIZE + displacement;
1790 /* Force the rebuild of the thunk at the next call */
1791 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1792 *vtable_slot = imt_trampoline;
1794 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1796 entries = get_generic_virtual_entries (domain, vtable_slot);
1798 sorted = imt_sort_slot_entries (entries);
1800 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1804 MonoImtBuilderEntry *next = entries->next;
1809 for (i = 0; i < sorted->len; ++i)
1810 g_free (g_ptr_array_index (sorted, i));
1811 g_ptr_array_free (sorted, TRUE);
1814 #ifndef __native_client__
1815 /* We don't re-use any thunks as there is a lot of overhead */
1816 /* to deleting and re-using code in Native Client. */
1817 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1818 invalidate_generic_virtual_thunk (domain, old_thunk);
1822 mono_domain_unlock (domain);
1825 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1828 * mono_class_vtable:
1829 * @domain: the application domain
1830 * @class: the class to initialize
1832 * VTables are domain specific because we create domain specific code, and
1833 * they contain the domain specific static class data.
1834 * On failure, NULL is returned, and class->exception_type is set.
1837 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1839 return mono_class_vtable_full (domain, klass, FALSE);
1843 * mono_class_vtable_full:
1844 * @domain: the application domain
1845 * @class: the class to initialize
1846 * @raise_on_error if an exception should be raised on failure or not
1848 * VTables are domain specific because we create domain specific code, and
1849 * they contain the domain specific static class data.
1852 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1854 MONO_REQ_GC_UNSAFE_MODE;
1856 MonoClassRuntimeInfo *runtime_info;
1860 if (klass->exception_type) {
1862 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1866 /* this check can be inlined in jitted code, too */
1867 runtime_info = klass->runtime_info;
1868 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1869 return runtime_info->domain_vtables [domain->domain_id];
1870 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1874 * mono_class_try_get_vtable:
1875 * @domain: the application domain
1876 * @class: the class to initialize
1878 * This function tries to get the associated vtable from @class if
1879 * it was already created.
1882 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1884 MONO_REQ_GC_NEUTRAL_MODE;
1886 MonoClassRuntimeInfo *runtime_info;
1890 runtime_info = klass->runtime_info;
1891 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1892 return runtime_info->domain_vtables [domain->domain_id];
1897 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1899 MONO_REQ_GC_NEUTRAL_MODE;
1901 size_t alloc_offset;
1904 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1905 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1906 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1908 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1909 g_assert ((imt_table_bytes & 7) == 4);
1916 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1920 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1922 MONO_REQ_GC_UNSAFE_MODE;
1925 MonoClassRuntimeInfo *runtime_info, *old_info;
1926 MonoClassField *field;
1928 int i, vtable_slots;
1929 size_t imt_table_bytes;
1931 guint32 vtable_size, class_size;
1933 gpointer *interface_offsets;
1935 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1936 mono_domain_lock (domain);
1937 runtime_info = klass->runtime_info;
1938 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1939 mono_domain_unlock (domain);
1940 mono_loader_unlock ();
1941 return runtime_info->domain_vtables [domain->domain_id];
1943 if (!klass->inited || klass->exception_type) {
1944 if (!mono_class_init (klass) || klass->exception_type) {
1945 mono_domain_unlock (domain);
1946 mono_loader_unlock ();
1948 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1953 /* Array types require that their element type be valid*/
1954 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1955 MonoClass *element_class = klass->element_class;
1956 if (!element_class->inited)
1957 mono_class_init (element_class);
1959 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1960 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1961 mono_class_setup_vtable (element_class);
1963 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1964 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1965 if (klass->exception_type == MONO_EXCEPTION_NONE)
1966 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1967 mono_domain_unlock (domain);
1968 mono_loader_unlock ();
1970 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1976 * For some classes, mono_class_init () already computed klass->vtable_size, and
1977 * that is all that is needed because of the vtable trampolines.
1979 if (!klass->vtable_size)
1980 mono_class_setup_vtable (klass);
1982 if (klass->generic_class && !klass->vtable)
1983 mono_class_check_vtable_constraints (klass, NULL);
1985 /* Initialize klass->has_finalize */
1986 mono_class_has_finalizer (klass);
1988 if (klass->exception_type) {
1989 mono_domain_unlock (domain);
1990 mono_loader_unlock ();
1992 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1996 vtable_slots = klass->vtable_size;
1997 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1998 class_size = mono_class_data_size (klass);
2002 if (klass->interface_offsets_count) {
2003 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2004 mono_stats.imt_number_of_tables++;
2005 mono_stats.imt_tables_size += imt_table_bytes;
2007 imt_table_bytes = 0;
2010 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2012 mono_stats.used_class_count++;
2013 mono_stats.class_vtable_size += vtable_size;
2015 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2016 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2017 g_assert (!((gsize)vt & 7));
2020 vt->rank = klass->rank;
2021 vt->domain = domain;
2023 mono_class_compute_gc_descriptor (klass);
2025 * We can't use typed allocation in the non-root domains, since the
2026 * collector needs the GC descriptor stored in the vtable even after
2027 * the mempool containing the vtable is destroyed when the domain is
2028 * unloaded. An alternative might be to allocate vtables in the GC
2029 * heap, but this does not seem to work (it leads to crashes inside
2030 * libgc). If that approach is tried, two gc descriptors need to be
2031 * allocated for each class: one for the root domain, and one for all
2032 * other domains. The second descriptor should contain a bit for the
2033 * vtable field in MonoObject, since we can no longer assume the
2034 * vtable is reachable by other roots after the appdomain is unloaded.
2036 #ifdef HAVE_BOEHM_GC
2037 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2038 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2041 vt->gc_descr = klass->gc_descr;
2043 gc_bits = mono_gc_get_vtable_bits (klass);
2044 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2046 vt->gc_bits = gc_bits;
2049 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2050 if (klass->has_static_refs) {
2051 MonoGCDescriptor statics_gc_descr;
2053 gsize default_bitmap [4] = {0};
2056 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2057 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2058 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2059 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2060 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2061 if (bitmap != default_bitmap)
2064 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2066 vt->has_static_fields = TRUE;
2067 mono_stats.class_static_data_size += class_size;
2071 while ((field = mono_class_get_fields (klass, &iter))) {
2072 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2074 if (mono_field_is_deleted (field))
2076 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2077 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2078 if (special_static != SPECIAL_STATIC_NONE) {
2079 guint32 size, offset;
2081 gsize default_bitmap [4] = {0};
2086 if (mono_type_is_reference (field->type)) {
2087 default_bitmap [0] = 1;
2089 bitmap = default_bitmap;
2090 } else if (mono_type_is_struct (field->type)) {
2091 fclass = mono_class_from_mono_type (field->type);
2092 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2093 numbits = max_set + 1;
2095 default_bitmap [0] = 0;
2097 bitmap = default_bitmap;
2099 size = mono_type_size (field->type, &align);
2100 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2101 if (!domain->special_static_fields)
2102 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2103 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2104 if (bitmap != default_bitmap)
2107 * This marks the field as special static to speed up the
2108 * checks in mono_field_static_get/set_value ().
2114 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2115 MonoClass *fklass = mono_class_from_mono_type (field->type);
2116 const char *data = mono_field_get_data (field);
2118 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2119 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2120 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2123 if (fklass->valuetype) {
2124 memcpy (t, data, mono_class_value_size (fklass, NULL));
2126 /* it's a pointer type: add check */
2127 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2134 vt->max_interface_id = klass->max_interface_id;
2135 vt->interface_bitmap = klass->interface_bitmap;
2137 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2138 // class->name, klass->interface_offsets_count);
2140 /* Initialize vtable */
2141 if (callbacks.get_vtable_trampoline) {
2142 // This also covers the AOT case
2143 for (i = 0; i < klass->vtable_size; ++i) {
2144 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2147 mono_class_setup_vtable (klass);
2149 for (i = 0; i < klass->vtable_size; ++i) {
2152 if ((cm = klass->vtable [i]))
2153 vt->vtable [i] = arch_create_jit_trampoline (cm);
2157 if (imt_table_bytes) {
2158 /* Now that the vtable is full, we can actually fill up the IMT */
2159 for (i = 0; i < MONO_IMT_SIZE; ++i)
2160 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2164 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2165 * re-acquire them and check if another thread has created the vtable in the meantime.
2167 /* Special case System.MonoType to avoid infinite recursion */
2168 if (klass != mono_defaults.monotype_class) {
2169 /*FIXME check for OOM*/
2170 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2171 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2172 /* This is unregistered in
2173 unregister_vtable_reflection_type() in
2175 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2178 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2180 /* class_vtable_array keeps an array of created vtables
2182 g_ptr_array_add (domain->class_vtable_array, vt);
2183 /* klass->runtime_info is protected by the loader lock, both when
2184 * it it enlarged and when it is stored info.
2188 * Store the vtable in klass->runtime_info.
2189 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2191 mono_memory_barrier ();
2193 old_info = klass->runtime_info;
2194 if (old_info && old_info->max_domain >= domain->domain_id) {
2195 /* someone already created a large enough runtime info */
2196 old_info->domain_vtables [domain->domain_id] = vt;
2198 int new_size = domain->domain_id;
2200 new_size = MAX (new_size, old_info->max_domain);
2202 /* make the new size a power of two */
2204 while (new_size > i)
2207 /* this is a bounded memory retention issue: may want to
2208 * handle it differently when we'll have a rcu-like system.
2210 runtime_info = mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2211 runtime_info->max_domain = new_size - 1;
2212 /* copy the stuff from the older info */
2214 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2216 runtime_info->domain_vtables [domain->domain_id] = vt;
2218 mono_memory_barrier ();
2219 klass->runtime_info = runtime_info;
2222 if (klass == mono_defaults.monotype_class) {
2223 /*FIXME check for OOM*/
2224 vt->type = mono_type_get_object (domain, &klass->byval_arg);
2225 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2226 /* This is unregistered in
2227 unregister_vtable_reflection_type() in
2229 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2232 mono_domain_unlock (domain);
2233 mono_loader_unlock ();
2235 /* make sure the parent is initialized */
2236 /*FIXME shouldn't this fail the current type?*/
2238 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2243 #ifndef DISABLE_REMOTING
2245 * mono_class_proxy_vtable:
2246 * @domain: the application domain
2247 * @remove_class: the remote class
2249 * Creates a vtable for transparent proxies. It is basically
2250 * a copy of the real vtable of the class wrapped in @remote_class,
2251 * but all function pointers invoke the remoting functions, and
2252 * vtable->klass points to the transparent proxy class, and not to @class.
2255 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2257 MONO_REQ_GC_UNSAFE_MODE;
2260 MonoVTable *vt, *pvt;
2261 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2263 GSList *extra_interfaces = NULL;
2264 MonoClass *klass = remote_class->proxy_class;
2265 gpointer *interface_offsets;
2268 size_t imt_table_bytes;
2270 #ifdef COMPRESSED_INTERFACE_BITMAP
2274 vt = mono_class_vtable (domain, klass);
2275 g_assert (vt); /*FIXME property handle failure*/
2276 max_interface_id = vt->max_interface_id;
2278 /* Calculate vtable space for extra interfaces */
2279 for (j = 0; j < remote_class->interface_count; j++) {
2280 MonoClass* iclass = remote_class->interfaces[j];
2284 /*FIXME test for interfaces with variant generic arguments*/
2285 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2286 continue; /* interface implemented by the class */
2287 if (g_slist_find (extra_interfaces, iclass))
2290 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2292 method_count = mono_class_num_methods (iclass);
2294 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2295 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2297 for (i = 0; i < ifaces->len; ++i) {
2298 MonoClass *ic = g_ptr_array_index (ifaces, i);
2299 /*FIXME test for interfaces with variant generic arguments*/
2300 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2301 continue; /* interface implemented by the class */
2302 if (g_slist_find (extra_interfaces, ic))
2304 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2305 method_count += mono_class_num_methods (ic);
2307 g_ptr_array_free (ifaces, TRUE);
2310 extra_interface_vtsize += method_count * sizeof (gpointer);
2311 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2314 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2315 mono_stats.imt_number_of_tables++;
2316 mono_stats.imt_tables_size += imt_table_bytes;
2318 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2320 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2322 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2323 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2324 g_assert (!((gsize)pvt & 7));
2326 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2328 pvt->klass = mono_defaults.transparent_proxy_class;
2329 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2330 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2332 /* initialize vtable */
2333 mono_class_setup_vtable (klass);
2334 for (i = 0; i < klass->vtable_size; ++i) {
2337 if ((cm = klass->vtable [i]))
2338 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2340 pvt->vtable [i] = NULL;
2343 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2344 /* create trampolines for abstract methods */
2345 for (k = klass; k; k = k->parent) {
2347 gpointer iter = NULL;
2348 while ((m = mono_class_get_methods (k, &iter)))
2349 if (!pvt->vtable [m->slot])
2350 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2354 pvt->max_interface_id = max_interface_id;
2355 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2356 #ifdef COMPRESSED_INTERFACE_BITMAP
2357 bitmap = g_malloc0 (bsize);
2359 bitmap = mono_domain_alloc0 (domain, bsize);
2362 for (i = 0; i < klass->interface_offsets_count; ++i) {
2363 int interface_id = klass->interfaces_packed [i]->interface_id;
2364 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2367 if (extra_interfaces) {
2368 int slot = klass->vtable_size;
2374 /* Create trampolines for the methods of the interfaces */
2375 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2376 interf = list_item->data;
2378 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2382 while ((cm = mono_class_get_methods (interf, &iter)))
2383 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2385 slot += mono_class_num_methods (interf);
2389 /* Now that the vtable is full, we can actually fill up the IMT */
2390 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2391 if (extra_interfaces) {
2392 g_slist_free (extra_interfaces);
2395 #ifdef COMPRESSED_INTERFACE_BITMAP
2396 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2397 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2398 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2401 pvt->interface_bitmap = bitmap;
2406 #endif /* DISABLE_REMOTING */
2409 * mono_class_field_is_special_static:
2411 * Returns whether @field is a thread/context static field.
2414 mono_class_field_is_special_static (MonoClassField *field)
2416 MONO_REQ_GC_NEUTRAL_MODE
2418 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2420 if (mono_field_is_deleted (field))
2422 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2423 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2430 * mono_class_field_get_special_static_type:
2431 * @field: The MonoClassField describing the field.
2433 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2434 * SPECIAL_STATIC_NONE otherwise.
2437 mono_class_field_get_special_static_type (MonoClassField *field)
2439 MONO_REQ_GC_NEUTRAL_MODE
2441 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2442 return SPECIAL_STATIC_NONE;
2443 if (mono_field_is_deleted (field))
2444 return SPECIAL_STATIC_NONE;
2445 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2446 return field_is_special_static (field->parent, field);
2447 return SPECIAL_STATIC_NONE;
2451 * mono_class_has_special_static_fields:
2453 * Returns whenever @klass has any thread/context static fields.
2456 mono_class_has_special_static_fields (MonoClass *klass)
2458 MONO_REQ_GC_NEUTRAL_MODE
2460 MonoClassField *field;
2464 while ((field = mono_class_get_fields (klass, &iter))) {
2465 g_assert (field->parent == klass);
2466 if (mono_class_field_is_special_static (field))
2473 #ifndef DISABLE_REMOTING
2475 * create_remote_class_key:
2476 * Creates an array of pointers that can be used as a hash key for a remote class.
2477 * The first element of the array is the number of pointers.
2480 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2482 MONO_REQ_GC_NEUTRAL_MODE;
2487 if (remote_class == NULL) {
2488 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2489 key = g_malloc (sizeof(gpointer) * 3);
2490 key [0] = GINT_TO_POINTER (2);
2491 key [1] = mono_defaults.marshalbyrefobject_class;
2492 key [2] = extra_class;
2494 key = g_malloc (sizeof(gpointer) * 2);
2495 key [0] = GINT_TO_POINTER (1);
2496 key [1] = extra_class;
2499 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2500 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2501 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2502 key [1] = remote_class->proxy_class;
2504 // Keep the list of interfaces sorted
2505 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2506 if (extra_class && remote_class->interfaces [i] > extra_class) {
2507 key [j++] = extra_class;
2510 key [j] = remote_class->interfaces [i];
2513 key [j] = extra_class;
2515 // Replace the old class. The interface list is the same
2516 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2517 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2518 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2519 for (i = 0; i < remote_class->interface_count; i++)
2520 key [2 + i] = remote_class->interfaces [i];
2528 * copy_remote_class_key:
2530 * Make a copy of KEY in the domain and return the copy.
2533 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2535 MONO_REQ_GC_NEUTRAL_MODE
2537 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2538 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2540 memcpy (mp_key, key, key_size);
2546 * mono_remote_class:
2547 * @domain: the application domain
2548 * @class_name: name of the remote class
2550 * Creates and initializes a MonoRemoteClass object for a remote type.
2552 * Can raise an exception on failure.
2555 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2557 MONO_REQ_GC_UNSAFE_MODE;
2560 MonoRemoteClass *rc;
2561 gpointer* key, *mp_key;
2564 key = create_remote_class_key (NULL, proxy_class);
2566 mono_domain_lock (domain);
2567 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2571 mono_domain_unlock (domain);
2575 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2576 if (!mono_error_ok (&error)) {
2578 mono_domain_unlock (domain);
2579 mono_error_raise_exception (&error);
2582 mp_key = copy_remote_class_key (domain, key);
2586 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2587 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2588 rc->interface_count = 1;
2589 rc->interfaces [0] = proxy_class;
2590 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2592 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2593 rc->interface_count = 0;
2594 rc->proxy_class = proxy_class;
2597 rc->default_vtable = NULL;
2598 rc->xdomain_vtable = NULL;
2599 rc->proxy_class_name = name;
2600 #ifndef DISABLE_PERFCOUNTERS
2601 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2604 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2606 mono_domain_unlock (domain);
2611 * clone_remote_class:
2612 * Creates a copy of the remote_class, adding the provided class or interface
2614 static MonoRemoteClass*
2615 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2617 MONO_REQ_GC_NEUTRAL_MODE;
2619 MonoRemoteClass *rc;
2620 gpointer* key, *mp_key;
2622 key = create_remote_class_key (remote_class, extra_class);
2623 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2629 mp_key = copy_remote_class_key (domain, key);
2633 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2635 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2636 rc->proxy_class = remote_class->proxy_class;
2637 rc->interface_count = remote_class->interface_count + 1;
2639 // Keep the list of interfaces sorted, since the hash key of
2640 // the remote class depends on this
2641 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2642 if (remote_class->interfaces [i] > extra_class && i == j)
2643 rc->interfaces [j++] = extra_class;
2644 rc->interfaces [j] = remote_class->interfaces [i];
2647 rc->interfaces [j] = extra_class;
2649 // Replace the old class. The interface array is the same
2650 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2651 rc->proxy_class = extra_class;
2652 rc->interface_count = remote_class->interface_count;
2653 if (rc->interface_count > 0)
2654 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2657 rc->default_vtable = NULL;
2658 rc->xdomain_vtable = NULL;
2659 rc->proxy_class_name = remote_class->proxy_class_name;
2661 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2667 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2669 MONO_REQ_GC_UNSAFE_MODE;
2671 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2672 mono_domain_lock (domain);
2673 if (rp->target_domain_id != -1) {
2674 if (remote_class->xdomain_vtable == NULL)
2675 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2676 mono_domain_unlock (domain);
2677 mono_loader_unlock ();
2678 return remote_class->xdomain_vtable;
2680 if (remote_class->default_vtable == NULL) {
2683 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2684 klass = mono_class_from_mono_type (type);
2686 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)))
2687 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2690 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2693 mono_domain_unlock (domain);
2694 mono_loader_unlock ();
2695 return remote_class->default_vtable;
2699 * mono_upgrade_remote_class:
2700 * @domain: the application domain
2701 * @tproxy: the proxy whose remote class has to be upgraded.
2702 * @klass: class to which the remote class can be casted.
2704 * Updates the vtable of the remote class by adding the necessary method slots
2705 * and interface offsets so it can be safely casted to klass. klass can be a
2706 * class or an interface.
2709 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2711 MONO_REQ_GC_UNSAFE_MODE;
2713 MonoTransparentProxy *tproxy;
2714 MonoRemoteClass *remote_class;
2715 gboolean redo_vtable;
2717 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2718 mono_domain_lock (domain);
2720 tproxy = (MonoTransparentProxy*) proxy_object;
2721 remote_class = tproxy->remote_class;
2723 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2726 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2727 if (remote_class->interfaces [i] == klass)
2728 redo_vtable = FALSE;
2731 redo_vtable = (remote_class->proxy_class != klass);
2735 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2736 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2739 mono_domain_unlock (domain);
2740 mono_loader_unlock ();
2742 #endif /* DISABLE_REMOTING */
2746 * mono_object_get_virtual_method:
2747 * @obj: object to operate on.
2750 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2751 * the instance of a callvirt of method.
2754 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2756 MONO_REQ_GC_UNSAFE_MODE;
2759 MonoMethod **vtable;
2760 gboolean is_proxy = FALSE;
2761 MonoMethod *res = NULL;
2763 klass = mono_object_class (obj);
2764 #ifndef DISABLE_REMOTING
2765 if (klass == mono_defaults.transparent_proxy_class) {
2766 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2771 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2774 mono_class_setup_vtable (klass);
2775 vtable = klass->vtable;
2777 if (method->slot == -1) {
2778 /* method->slot might not be set for instances of generic methods */
2779 if (method->is_inflated) {
2780 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2781 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2784 g_assert_not_reached ();
2788 /* check method->slot is a valid index: perform isinstance? */
2789 if (method->slot != -1) {
2790 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2792 gboolean variance_used = FALSE;
2793 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2794 g_assert (iface_offset > 0);
2795 res = vtable [iface_offset + method->slot];
2798 res = vtable [method->slot];
2802 #ifndef DISABLE_REMOTING
2804 /* It may be an interface, abstract class method or generic method */
2805 if (!res || mono_method_signature (res)->generic_param_count)
2808 /* generic methods demand invoke_with_check */
2809 if (mono_method_signature (res)->generic_param_count)
2810 res = mono_marshal_get_remoting_invoke_with_check (res);
2813 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2814 res = mono_cominterop_get_invoke (res);
2817 res = mono_marshal_get_remoting_invoke (res);
2822 if (method->is_inflated) {
2824 /* Have to inflate the result */
2825 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2826 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2836 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2838 g_error ("runtime invoke called on uninitialized runtime");
2842 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2845 * mono_runtime_invoke:
2846 * @method: method to invoke
2847 * @obJ: object instance
2848 * @params: arguments to the method
2849 * @exc: exception information.
2851 * Invokes the method represented by @method on the object @obj.
2853 * obj is the 'this' pointer, it should be NULL for static
2854 * methods, a MonoObject* for object instances and a pointer to
2855 * the value type for value types.
2857 * The params array contains the arguments to the method with the
2858 * same convention: MonoObject* pointers for object instances and
2859 * pointers to the value type otherwise.
2861 * From unmanaged code you'll usually use the
2862 * mono_runtime_invoke() variant.
2864 * Note that this function doesn't handle virtual methods for
2865 * you, it will exec the exact method you pass: we still need to
2866 * expose a function to lookup the derived class implementation
2867 * of a virtual method (there are examples of this in the code,
2870 * You can pass NULL as the exc argument if you don't want to
2871 * catch exceptions, otherwise, *exc will be set to the exception
2872 * thrown, if any. if an exception is thrown, you can't use the
2873 * MonoObject* result from the function.
2875 * If the method returns a value type, it is boxed in an object
2879 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2881 MONO_REQ_GC_UNSAFE_MODE;
2885 if (mono_runtime_get_no_exec ())
2886 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2888 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2889 mono_profiler_method_start_invoke (method);
2891 result = default_mono_runtime_invoke (method, obj, params, exc);
2893 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2894 mono_profiler_method_end_invoke (method);
2900 * mono_method_get_unmanaged_thunk:
2901 * @method: method to generate a thunk for.
2903 * Returns an unmanaged->managed thunk that can be used to call
2904 * a managed method directly from C.
2906 * The thunk's C signature closely matches the managed signature:
2908 * C#: public bool Equals (object obj);
2909 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2910 * MonoObject*, MonoException**);
2912 * The 1st ("this") parameter must not be used with static methods:
2914 * C#: public static bool ReferenceEquals (object a, object b);
2915 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2918 * The last argument must be a non-null pointer of a MonoException* pointer.
2919 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2920 * exception has been thrown in managed code. Otherwise it will point
2921 * to the MonoException* caught by the thunk. In this case, the result of
2922 * the thunk is undefined:
2924 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2925 * MonoException *ex = NULL;
2926 * Equals func = mono_method_get_unmanaged_thunk (method);
2927 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2929 * // handle exception
2932 * The calling convention of the thunk matches the platform's default
2933 * convention. This means that under Windows, C declarations must
2934 * contain the __stdcall attribute:
2936 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2937 * MonoObject*, MonoException**);
2941 * Value type arguments and return values are treated as they were objects:
2943 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2944 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2946 * Arguments must be properly boxed upon trunk's invocation, while return
2947 * values must be unboxed.
2950 mono_method_get_unmanaged_thunk (MonoMethod *method)
2952 MONO_REQ_GC_NEUTRAL_MODE;
2953 MONO_REQ_API_ENTRYPOINT;
2957 MONO_PREPARE_RESET_BLOCKING
2958 method = mono_marshal_get_thunk_invoke_wrapper (method);
2959 res = mono_compile_method (method);
2960 MONO_FINISH_RESET_BLOCKING
2966 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2968 MONO_REQ_GC_UNSAFE_MODE;
2972 /* object fields cannot be byref, so we don't need a
2974 gpointer *p = (gpointer*)dest;
2981 case MONO_TYPE_BOOLEAN:
2983 case MONO_TYPE_U1: {
2984 guint8 *p = (guint8*)dest;
2985 *p = value ? *(guint8*)value : 0;
2990 case MONO_TYPE_CHAR: {
2991 guint16 *p = (guint16*)dest;
2992 *p = value ? *(guint16*)value : 0;
2995 #if SIZEOF_VOID_P == 4
3000 case MONO_TYPE_U4: {
3001 gint32 *p = (gint32*)dest;
3002 *p = value ? *(gint32*)value : 0;
3005 #if SIZEOF_VOID_P == 8
3010 case MONO_TYPE_U8: {
3011 gint64 *p = (gint64*)dest;
3012 *p = value ? *(gint64*)value : 0;
3015 case MONO_TYPE_R4: {
3016 float *p = (float*)dest;
3017 *p = value ? *(float*)value : 0;
3020 case MONO_TYPE_R8: {
3021 double *p = (double*)dest;
3022 *p = value ? *(double*)value : 0;
3025 case MONO_TYPE_STRING:
3026 case MONO_TYPE_SZARRAY:
3027 case MONO_TYPE_CLASS:
3028 case MONO_TYPE_OBJECT:
3029 case MONO_TYPE_ARRAY:
3030 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
3032 case MONO_TYPE_FNPTR:
3033 case MONO_TYPE_PTR: {
3034 gpointer *p = (gpointer*)dest;
3035 *p = deref_pointer? *(gpointer*)value: value;
3038 case MONO_TYPE_VALUETYPE:
3039 /* note that 't' and 'type->type' can be different */
3040 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3041 t = mono_class_enum_basetype (type->data.klass)->type;
3044 MonoClass *klass = mono_class_from_mono_type (type);
3045 int size = mono_class_value_size (klass, NULL);
3047 mono_gc_bzero_atomic (dest, size);
3049 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3052 case MONO_TYPE_GENERICINST:
3053 t = type->data.generic_class->container_class->byval_arg.type;
3056 g_error ("got type %x", type->type);
3061 * mono_field_set_value:
3062 * @obj: Instance object
3063 * @field: MonoClassField describing the field to set
3064 * @value: The value to be set
3066 * Sets the value of the field described by @field in the object instance @obj
3067 * to the value passed in @value. This method should only be used for instance
3068 * fields. For static fields, use mono_field_static_set_value.
3070 * The value must be on the native format of the field type.
3073 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3075 MONO_REQ_GC_UNSAFE_MODE;
3079 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3081 dest = (char*)obj + field->offset;
3082 mono_copy_value (field->type, dest, value, FALSE);
3086 * mono_field_static_set_value:
3087 * @field: MonoClassField describing the field to set
3088 * @value: The value to be set
3090 * Sets the value of the static field described by @field
3091 * to the value passed in @value.
3093 * The value must be on the native format of the field type.
3096 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3098 MONO_REQ_GC_UNSAFE_MODE;
3102 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3103 /* you cant set a constant! */
3104 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3106 if (field->offset == -1) {
3107 /* Special static */
3110 mono_domain_lock (vt->domain);
3111 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3112 mono_domain_unlock (vt->domain);
3113 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3115 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3117 mono_copy_value (field->type, dest, value, FALSE);
3121 * mono_vtable_get_static_field_data:
3123 * Internal use function: return a pointer to the memory holding the static fields
3124 * for a class or NULL if there are no static fields.
3125 * This is exported only for use by the debugger.
3128 mono_vtable_get_static_field_data (MonoVTable *vt)
3130 MONO_REQ_GC_NEUTRAL_MODE
3132 if (!vt->has_static_fields)
3134 return vt->vtable [vt->klass->vtable_size];
3138 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3140 MONO_REQ_GC_UNSAFE_MODE;
3144 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3145 if (field->offset == -1) {
3146 /* Special static */
3149 mono_domain_lock (vt->domain);
3150 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3151 mono_domain_unlock (vt->domain);
3152 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3154 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3157 src = (guint8*)obj + field->offset;
3164 * mono_field_get_value:
3165 * @obj: Object instance
3166 * @field: MonoClassField describing the field to fetch information from
3167 * @value: pointer to the location where the value will be stored
3169 * Use this routine to get the value of the field @field in the object
3172 * The pointer provided by value must be of the field type, for reference
3173 * types this is a MonoObject*, for value types its the actual pointer to
3178 * mono_field_get_value (obj, int_field, &i);
3181 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3183 MONO_REQ_GC_UNSAFE_MODE;
3189 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3191 src = (char*)obj + field->offset;
3192 mono_copy_value (field->type, value, src, TRUE);
3196 * mono_field_get_value_object:
3197 * @domain: domain where the object will be created (if boxing)
3198 * @field: MonoClassField describing the field to fetch information from
3199 * @obj: The object instance for the field.
3201 * Returns: a new MonoObject with the value from the given field. If the
3202 * field represents a value type, the value is boxed.
3206 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3208 MONO_REQ_GC_UNSAFE_MODE;
3212 MonoVTable *vtable = NULL;
3214 gboolean is_static = FALSE;
3215 gboolean is_ref = FALSE;
3216 gboolean is_literal = FALSE;
3217 gboolean is_ptr = FALSE;
3219 MonoType *type = mono_field_get_type_checked (field, &error);
3221 if (!mono_error_ok (&error))
3222 mono_error_raise_exception (&error);
3224 switch (type->type) {
3225 case MONO_TYPE_STRING:
3226 case MONO_TYPE_OBJECT:
3227 case MONO_TYPE_CLASS:
3228 case MONO_TYPE_ARRAY:
3229 case MONO_TYPE_SZARRAY:
3234 case MONO_TYPE_BOOLEAN:
3237 case MONO_TYPE_CHAR:
3246 case MONO_TYPE_VALUETYPE:
3247 is_ref = type->byref;
3249 case MONO_TYPE_GENERICINST:
3250 is_ref = !mono_type_generic_inst_is_valuetype (type);
3256 g_error ("type 0x%x not handled in "
3257 "mono_field_get_value_object", type->type);
3261 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3264 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3268 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3269 if (!vtable->initialized)
3270 mono_runtime_class_init (vtable);
3278 get_default_field_value (domain, field, &o);
3279 } else if (is_static) {
3280 mono_field_static_get_value (vtable, field, &o);
3282 mono_field_get_value (obj, field, &o);
3288 static MonoMethod *m;
3294 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3295 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3301 get_default_field_value (domain, field, v);
3302 } else if (is_static) {
3303 mono_field_static_get_value (vtable, field, v);
3305 mono_field_get_value (obj, field, v);
3308 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3309 args [0] = ptr ? *ptr : NULL;
3310 args [1] = mono_type_get_object (mono_domain_get (), type);
3312 return mono_runtime_invoke (m, NULL, args, NULL);
3315 /* boxed value type */
3316 klass = mono_class_from_mono_type (type);
3318 if (mono_class_is_nullable (klass))
3319 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3321 o = mono_object_new (domain, klass);
3322 v = ((gchar *) o) + sizeof (MonoObject);
3325 get_default_field_value (domain, field, v);
3326 } else if (is_static) {
3327 mono_field_static_get_value (vtable, field, v);
3329 mono_field_get_value (obj, field, v);
3336 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3338 MONO_REQ_GC_UNSAFE_MODE;
3341 const char *p = blob;
3342 mono_metadata_decode_blob_size (p, &p);
3345 case MONO_TYPE_BOOLEAN:
3348 *(guint8 *) value = *p;
3350 case MONO_TYPE_CHAR:
3353 *(guint16*) value = read16 (p);
3357 *(guint32*) value = read32 (p);
3361 *(guint64*) value = read64 (p);
3364 readr4 (p, (float*) value);
3367 readr8 (p, (double*) value);
3369 case MONO_TYPE_STRING:
3370 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3372 case MONO_TYPE_CLASS:
3373 *(gpointer*) value = NULL;
3377 g_warning ("type 0x%02x should not be in constant table", type);
3383 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3385 MONO_REQ_GC_NEUTRAL_MODE;
3387 MonoTypeEnum def_type;
3390 data = mono_class_get_field_default_value (field, &def_type);
3391 mono_get_constant_value_from_blob (domain, def_type, data, value);
3395 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3397 MONO_REQ_GC_UNSAFE_MODE;
3401 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3403 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3404 get_default_field_value (vt->domain, field, value);
3408 if (field->offset == -1) {
3409 /* Special static */
3410 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3411 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3413 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3415 mono_copy_value (field->type, value, src, TRUE);
3419 * mono_field_static_get_value:
3420 * @vt: vtable to the object
3421 * @field: MonoClassField describing the field to fetch information from
3422 * @value: where the value is returned
3424 * Use this routine to get the value of the static field @field value.
3426 * The pointer provided by value must be of the field type, for reference
3427 * types this is a MonoObject*, for value types its the actual pointer to
3432 * mono_field_static_get_value (vt, int_field, &i);
3435 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3437 MONO_REQ_GC_NEUTRAL_MODE;
3439 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3443 * mono_property_set_value:
3444 * @prop: MonoProperty to set
3445 * @obj: instance object on which to act
3446 * @params: parameters to pass to the propery
3447 * @exc: optional exception
3449 * Invokes the property's set method with the given arguments on the
3450 * object instance obj (or NULL for static properties).
3452 * You can pass NULL as the exc argument if you don't want to
3453 * catch exceptions, otherwise, *exc will be set to the exception
3454 * thrown, if any. if an exception is thrown, you can't use the
3455 * MonoObject* result from the function.
3458 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3460 MONO_REQ_GC_UNSAFE_MODE;
3462 default_mono_runtime_invoke (prop->set, obj, params, exc);
3466 * mono_property_get_value:
3467 * @prop: MonoProperty to fetch
3468 * @obj: instance object on which to act
3469 * @params: parameters to pass to the propery
3470 * @exc: optional exception
3472 * Invokes the property's get method with the given arguments on the
3473 * object instance obj (or NULL for static properties).
3475 * You can pass NULL as the exc argument if you don't want to
3476 * catch exceptions, otherwise, *exc will be set to the exception
3477 * thrown, if any. if an exception is thrown, you can't use the
3478 * MonoObject* result from the function.
3480 * Returns: the value from invoking the get method on the property.
3483 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3485 MONO_REQ_GC_UNSAFE_MODE;
3487 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3491 * mono_nullable_init:
3492 * @buf: The nullable structure to initialize.
3493 * @value: the value to initialize from
3494 * @klass: the type for the object
3496 * Initialize the nullable structure pointed to by @buf from @value which
3497 * should be a boxed value type. The size of @buf should be able to hold
3498 * as much data as the @klass->instance_size (which is the number of bytes
3499 * that will be copies).
3501 * Since Nullables have variable structure, we can not define a C
3502 * structure for them.
3505 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3507 MONO_REQ_GC_UNSAFE_MODE;
3509 MonoClass *param_class = klass->cast_class;
3511 mono_class_setup_fields_locking (klass);
3512 g_assert (klass->fields_inited);
3514 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3515 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3517 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3519 if (param_class->has_references)
3520 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3522 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3524 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3529 * mono_nullable_box:
3530 * @buf: The buffer representing the data to be boxed
3531 * @klass: the type to box it as.
3533 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3537 mono_nullable_box (guint8 *buf, MonoClass *klass)
3539 MONO_REQ_GC_UNSAFE_MODE;
3541 MonoClass *param_class = klass->cast_class;
3543 mono_class_setup_fields_locking (klass);
3544 g_assert (klass->fields_inited);
3546 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3547 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3549 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3550 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3551 if (param_class->has_references)
3552 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3554 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3562 * mono_get_delegate_invoke:
3563 * @klass: The delegate class
3565 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3568 mono_get_delegate_invoke (MonoClass *klass)
3570 MONO_REQ_GC_NEUTRAL_MODE;
3574 /* This is called at runtime, so avoid the slower search in metadata */
3575 mono_class_setup_methods (klass);
3576 if (klass->exception_type)
3578 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3583 * mono_get_delegate_begin_invoke:
3584 * @klass: The delegate class
3586 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3589 mono_get_delegate_begin_invoke (MonoClass *klass)
3591 MONO_REQ_GC_NEUTRAL_MODE;
3595 /* This is called at runtime, so avoid the slower search in metadata */
3596 mono_class_setup_methods (klass);
3597 if (klass->exception_type)
3599 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3604 * mono_get_delegate_end_invoke:
3605 * @klass: The delegate class
3607 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3610 mono_get_delegate_end_invoke (MonoClass *klass)
3612 MONO_REQ_GC_NEUTRAL_MODE;
3616 /* This is called at runtime, so avoid the slower search in metadata */
3617 mono_class_setup_methods (klass);
3618 if (klass->exception_type)
3620 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3625 * mono_runtime_delegate_invoke:
3626 * @delegate: pointer to a delegate object.
3627 * @params: parameters for the delegate.
3628 * @exc: Pointer to the exception result.
3630 * Invokes the delegate method @delegate with the parameters provided.
3632 * You can pass NULL as the exc argument if you don't want to
3633 * catch exceptions, otherwise, *exc will be set to the exception
3634 * thrown, if any. if an exception is thrown, you can't use the
3635 * MonoObject* result from the function.
3638 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3640 MONO_REQ_GC_UNSAFE_MODE;
3643 MonoClass *klass = delegate->vtable->klass;
3645 im = mono_get_delegate_invoke (klass);
3647 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3649 return mono_runtime_invoke (im, delegate, params, exc);
3652 static char **main_args = NULL;
3653 static int num_main_args = 0;
3656 * mono_runtime_get_main_args:
3658 * Returns: a MonoArray with the arguments passed to the main program
3661 mono_runtime_get_main_args (void)
3663 MONO_REQ_GC_UNSAFE_MODE;
3667 MonoDomain *domain = mono_domain_get ();
3669 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3671 for (i = 0; i < num_main_args; ++i)
3672 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3678 free_main_args (void)
3680 MONO_REQ_GC_NEUTRAL_MODE;
3684 for (i = 0; i < num_main_args; ++i)
3685 g_free (main_args [i]);
3692 * mono_runtime_set_main_args:
3693 * @argc: number of arguments from the command line
3694 * @argv: array of strings from the command line
3696 * Set the command line arguments from an embedding application that doesn't otherwise call
3697 * mono_runtime_run_main ().
3700 mono_runtime_set_main_args (int argc, char* argv[])
3702 MONO_REQ_GC_NEUTRAL_MODE;
3707 main_args = g_new0 (char*, argc);
3708 num_main_args = argc;
3710 for (i = 0; i < argc; ++i) {
3713 utf8_arg = mono_utf8_from_external (argv[i]);
3714 if (utf8_arg == NULL) {
3715 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3716 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3720 main_args [i] = utf8_arg;
3727 * mono_runtime_run_main:
3728 * @method: the method to start the application with (usually Main)
3729 * @argc: number of arguments from the command line
3730 * @argv: array of strings from the command line
3731 * @exc: excetption results
3733 * Execute a standard Main() method (argc/argv contains the
3734 * executable name). This method also sets the command line argument value
3735 * needed by System.Environment.
3740 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3743 MONO_REQ_GC_UNSAFE_MODE;
3746 MonoArray *args = NULL;
3747 MonoDomain *domain = mono_domain_get ();
3748 gchar *utf8_fullpath;
3749 MonoMethodSignature *sig;
3751 g_assert (method != NULL);
3753 mono_thread_set_main (mono_thread_current ());
3755 main_args = g_new0 (char*, argc);
3756 num_main_args = argc;
3758 if (!g_path_is_absolute (argv [0])) {
3759 gchar *basename = g_path_get_basename (argv [0]);
3760 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3764 utf8_fullpath = mono_utf8_from_external (fullpath);
3765 if(utf8_fullpath == NULL) {
3766 /* Printing the arg text will cause glib to
3767 * whinge about "Invalid UTF-8", but at least
3768 * its relevant, and shows the problem text
3771 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3772 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3779 utf8_fullpath = mono_utf8_from_external (argv[0]);
3780 if(utf8_fullpath == NULL) {
3781 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3782 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3787 main_args [0] = utf8_fullpath;
3789 for (i = 1; i < argc; ++i) {
3792 utf8_arg=mono_utf8_from_external (argv[i]);
3793 if(utf8_arg==NULL) {
3794 /* Ditto the comment about Invalid UTF-8 here */
3795 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3796 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3800 main_args [i] = utf8_arg;
3805 sig = mono_method_signature (method);
3807 g_print ("Unable to load Main method.\n");
3811 if (sig->param_count) {
3812 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3813 for (i = 0; i < argc; ++i) {
3814 /* The encodings should all work, given that
3815 * we've checked all these args for the
3818 gchar *str = mono_utf8_from_external (argv [i]);
3819 MonoString *arg = mono_string_new (domain, str);
3820 mono_array_setref (args, i, arg);
3824 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3827 mono_assembly_set_main (method->klass->image->assembly);
3829 return mono_runtime_exec_main (method, args, exc);
3833 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3835 static MonoMethod *serialize_method;
3840 if (!serialize_method) {
3841 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3842 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3845 if (!serialize_method) {
3850 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3854 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3862 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3864 MONO_REQ_GC_UNSAFE_MODE;
3866 static MonoMethod *deserialize_method;
3871 if (!deserialize_method) {
3872 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3873 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3875 if (!deserialize_method) {
3882 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3889 #ifndef DISABLE_REMOTING
3891 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3893 MONO_REQ_GC_UNSAFE_MODE;
3895 static MonoMethod *get_proxy_method;
3897 MonoDomain *domain = mono_domain_get ();
3898 MonoRealProxy *real_proxy;
3899 MonoReflectionType *reflection_type;
3900 MonoTransparentProxy *transparent_proxy;
3902 if (!get_proxy_method)
3903 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3905 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3907 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3908 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3910 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3911 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3914 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3918 return (MonoObject*) transparent_proxy;
3920 #endif /* DISABLE_REMOTING */
3923 * mono_object_xdomain_representation
3925 * @target_domain: a domain
3926 * @exc: pointer to a MonoObject*
3928 * Creates a representation of obj in the domain target_domain. This
3929 * is either a copy of obj arrived through via serialization and
3930 * deserialization or a proxy, depending on whether the object is
3931 * serializable or marshal by ref. obj must not be in target_domain.
3933 * If the object cannot be represented in target_domain, NULL is
3934 * returned and *exc is set to an appropriate exception.
3937 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3939 MONO_REQ_GC_UNSAFE_MODE;
3941 MonoObject *deserialized = NULL;
3942 gboolean failure = FALSE;
3946 #ifndef DISABLE_REMOTING
3947 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3948 deserialized = make_transparent_proxy (obj, &failure, exc);
3953 MonoDomain *domain = mono_domain_get ();
3954 MonoObject *serialized;
3956 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3957 serialized = serialize_object (obj, &failure, exc);
3958 mono_domain_set_internal_with_options (target_domain, FALSE);
3960 deserialized = deserialize_object (serialized, &failure, exc);
3961 if (domain != target_domain)
3962 mono_domain_set_internal_with_options (domain, FALSE);
3965 return deserialized;
3968 /* Used in call_unhandled_exception_delegate */
3970 create_unhandled_exception_eventargs (MonoObject *exc)
3972 MONO_REQ_GC_UNSAFE_MODE;
3976 MonoMethod *method = NULL;
3977 MonoBoolean is_terminating = TRUE;
3980 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3983 mono_class_init (klass);
3985 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3986 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3990 args [1] = &is_terminating;
3992 obj = mono_object_new (mono_domain_get (), klass);
3993 mono_runtime_invoke (method, obj, args, NULL);
3998 /* Used in mono_unhandled_exception */
4000 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4001 MONO_REQ_GC_UNSAFE_MODE;
4003 MonoObject *e = NULL;
4005 MonoDomain *current_domain = mono_domain_get ();
4007 if (domain != current_domain)
4008 mono_domain_set_internal_with_options (domain, FALSE);
4010 g_assert (domain == mono_object_domain (domain->domain));
4012 if (mono_object_domain (exc) != domain) {
4013 MonoObject *serialization_exc;
4015 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4017 if (serialization_exc) {
4019 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4022 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4023 "System.Runtime.Serialization", "SerializationException",
4024 "Could not serialize unhandled exception.");
4028 g_assert (mono_object_domain (exc) == domain);
4030 pa [0] = domain->domain;
4031 pa [1] = create_unhandled_exception_eventargs (exc);
4032 mono_runtime_delegate_invoke (delegate, pa, &e);
4034 if (domain != current_domain)
4035 mono_domain_set_internal_with_options (current_domain, FALSE);
4039 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4040 if (!mono_error_ok (&error)) {
4041 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4042 mono_error_cleanup (&error);
4044 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4050 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4053 * mono_runtime_unhandled_exception_policy_set:
4054 * @policy: the new policy
4056 * This is a VM internal routine.
4058 * Sets the runtime policy for handling unhandled exceptions.
4061 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4062 runtime_unhandled_exception_policy = policy;
4066 * mono_runtime_unhandled_exception_policy_get:
4068 * This is a VM internal routine.
4070 * Gets the runtime policy for handling unhandled exceptions.
4072 MonoRuntimeUnhandledExceptionPolicy
4073 mono_runtime_unhandled_exception_policy_get (void) {
4074 return runtime_unhandled_exception_policy;
4078 * mono_unhandled_exception:
4079 * @exc: exception thrown
4081 * This is a VM internal routine.
4083 * We call this function when we detect an unhandled exception
4084 * in the default domain.
4086 * It invokes the * UnhandledException event in AppDomain or prints
4087 * a warning to the console
4090 mono_unhandled_exception (MonoObject *exc)
4092 MONO_REQ_GC_UNSAFE_MODE;
4094 MonoClassField *field;
4095 MonoDomain *current_domain, *root_domain;
4096 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4098 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4101 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4104 current_domain = mono_domain_get ();
4105 root_domain = mono_get_root_domain ();
4107 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4108 if (current_domain != root_domain)
4109 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4111 /* set exitcode only if we will abort the process */
4112 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4113 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4114 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4116 mono_environment_exitcode_set (1);
4119 mono_print_unhandled_exception (exc);
4121 if (root_appdomain_delegate)
4122 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4123 if (current_appdomain_delegate)
4124 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4129 * mono_runtime_exec_managed_code:
4130 * @domain: Application domain
4131 * @main_func: function to invoke from the execution thread
4132 * @main_args: parameter to the main_func
4134 * Launch a new thread to execute a function
4136 * main_func is called back from the thread with main_args as the
4137 * parameter. The callback function is expected to start Main()
4138 * eventually. This function then waits for all managed threads to
4140 * It is not necesseray anymore to execute managed code in a subthread,
4141 * so this function should not be used anymore by default: just
4142 * execute the code and then call mono_thread_manage ().
4145 mono_runtime_exec_managed_code (MonoDomain *domain,
4146 MonoMainThreadFunc main_func,
4149 mono_thread_create (domain, main_func, main_args);
4151 mono_thread_manage ();
4155 * Execute a standard Main() method (args doesn't contain the
4159 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4161 MONO_REQ_GC_UNSAFE_MODE;
4166 MonoCustomAttrInfo* cinfo;
4167 gboolean has_stathread_attribute;
4168 MonoInternalThread* thread = mono_thread_internal_current ();
4174 domain = mono_object_domain (args);
4175 if (!domain->entry_assembly) {
4177 MonoAssembly *assembly;
4179 assembly = method->klass->image->assembly;
4180 domain->entry_assembly = assembly;
4181 /* Domains created from another domain already have application_base and configuration_file set */
4182 if (domain->setup->application_base == NULL) {
4183 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4186 if (domain->setup->configuration_file == NULL) {
4187 str = g_strconcat (assembly->image->name, ".config", NULL);
4188 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4190 mono_set_private_bin_path_from_config (domain);
4194 cinfo = mono_custom_attrs_from_method (method);
4196 static MonoClass *stathread_attribute = NULL;
4197 if (!stathread_attribute)
4198 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4199 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4201 mono_custom_attrs_free (cinfo);
4203 has_stathread_attribute = FALSE;
4205 if (has_stathread_attribute) {
4206 thread->apartment_state = ThreadApartmentState_STA;
4208 thread->apartment_state = ThreadApartmentState_MTA;
4210 mono_thread_init_apartment_state ();
4212 /* FIXME: check signature of method */
4213 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4215 res = mono_runtime_invoke (method, NULL, pa, exc);
4217 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4221 mono_environment_exitcode_set (rval);
4223 mono_runtime_invoke (method, NULL, pa, exc);
4227 /* If the return type of Main is void, only
4228 * set the exitcode if an exception was thrown
4229 * (we don't want to blow away an
4230 * explicitly-set exit code)
4233 mono_environment_exitcode_set (rval);
4241 * mono_install_runtime_invoke:
4242 * @func: Function to install
4244 * This is a VM internal routine
4247 mono_install_runtime_invoke (MonoInvokeFunc func)
4249 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4254 * mono_runtime_invoke_array:
4255 * @method: method to invoke
4256 * @obJ: object instance
4257 * @params: arguments to the method
4258 * @exc: exception information.
4260 * Invokes the method represented by @method on the object @obj.
4262 * obj is the 'this' pointer, it should be NULL for static
4263 * methods, a MonoObject* for object instances and a pointer to
4264 * the value type for value types.
4266 * The params array contains the arguments to the method with the
4267 * same convention: MonoObject* pointers for object instances and
4268 * pointers to the value type otherwise. The _invoke_array
4269 * variant takes a C# object[] as the params argument (MonoArray
4270 * *params): in this case the value types are boxed inside the
4271 * respective reference representation.
4273 * From unmanaged code you'll usually use the
4274 * mono_runtime_invoke() variant.
4276 * Note that this function doesn't handle virtual methods for
4277 * you, it will exec the exact method you pass: we still need to
4278 * expose a function to lookup the derived class implementation
4279 * of a virtual method (there are examples of this in the code,
4282 * You can pass NULL as the exc argument if you don't want to
4283 * catch exceptions, otherwise, *exc will be set to the exception
4284 * thrown, if any. if an exception is thrown, you can't use the
4285 * MonoObject* result from the function.
4287 * If the method returns a value type, it is boxed in an object
4291 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4294 MONO_REQ_GC_UNSAFE_MODE;
4296 MonoMethodSignature *sig = mono_method_signature (method);
4297 gpointer *pa = NULL;
4300 gboolean has_byref_nullables = FALSE;
4302 if (NULL != params) {
4303 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4304 for (i = 0; i < mono_array_length (params); i++) {
4305 MonoType *t = sig->params [i];
4311 case MONO_TYPE_BOOLEAN:
4314 case MONO_TYPE_CHAR:
4323 case MONO_TYPE_VALUETYPE:
4324 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4325 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4326 pa [i] = mono_array_get (params, MonoObject*, i);
4328 has_byref_nullables = TRUE;
4330 /* MS seems to create the objects if a null is passed in */
4331 if (!mono_array_get (params, MonoObject*, i))
4332 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4336 * We can't pass the unboxed vtype byref to the callee, since
4337 * that would mean the callee would be able to modify boxed
4338 * primitive types. So we (and MS) make a copy of the boxed
4339 * object, pass that to the callee, and replace the original
4340 * boxed object in the arg array with the copy.
4342 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4343 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4344 mono_array_setref (params, i, copy);
4347 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4350 case MONO_TYPE_STRING:
4351 case MONO_TYPE_OBJECT:
4352 case MONO_TYPE_CLASS:
4353 case MONO_TYPE_ARRAY:
4354 case MONO_TYPE_SZARRAY:
4356 pa [i] = mono_array_addr (params, MonoObject*, i);
4357 // FIXME: I need to check this code path
4359 pa [i] = mono_array_get (params, MonoObject*, i);
4361 case MONO_TYPE_GENERICINST:
4363 t = &t->data.generic_class->container_class->this_arg;
4365 t = &t->data.generic_class->container_class->byval_arg;
4367 case MONO_TYPE_PTR: {
4370 /* The argument should be an IntPtr */
4371 arg = mono_array_get (params, MonoObject*, i);
4375 g_assert (arg->vtable->klass == mono_defaults.int_class);
4376 pa [i] = ((MonoIntPtr*)arg)->m_value;
4381 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4386 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4389 if (mono_class_is_nullable (method->klass)) {
4390 /* Need to create a boxed vtype instead */
4396 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4400 obj = mono_object_new (mono_domain_get (), method->klass);
4401 g_assert (obj); /*maybe we should raise a TLE instead?*/
4402 #ifndef DISABLE_REMOTING
4403 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4404 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4407 if (method->klass->valuetype)
4408 o = mono_object_unbox (obj);
4411 } else if (method->klass->valuetype) {
4412 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4415 mono_runtime_invoke (method, o, pa, exc);
4418 if (mono_class_is_nullable (method->klass)) {
4419 MonoObject *nullable;
4421 /* Convert the unboxed vtype into a Nullable structure */
4422 nullable = mono_object_new (mono_domain_get (), method->klass);
4424 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4425 obj = mono_object_unbox (nullable);
4428 /* obj must be already unboxed if needed */
4429 res = mono_runtime_invoke (method, obj, pa, exc);
4431 if (sig->ret->type == MONO_TYPE_PTR) {
4432 MonoClass *pointer_class;
4433 static MonoMethod *box_method;
4435 MonoObject *box_exc;
4438 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4439 * convert it to a Pointer object.
4441 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4443 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4445 g_assert (res->vtable->klass == mono_defaults.int_class);
4446 box_args [0] = ((MonoIntPtr*)res)->m_value;
4447 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4448 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4449 g_assert (!box_exc);
4452 if (has_byref_nullables) {
4454 * The runtime invoke wrapper already converted byref nullables back,
4455 * and stored them in pa, we just need to copy them back to the
4458 for (i = 0; i < mono_array_length (params); i++) {
4459 MonoType *t = sig->params [i];
4461 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4462 mono_array_setref (params, i, pa [i]);
4471 arith_overflow (void)
4473 MONO_REQ_GC_UNSAFE_MODE;
4475 mono_raise_exception (mono_get_exception_overflow ());
4480 * @klass: the class of the object that we want to create
4482 * Returns: a newly created object whose definition is
4483 * looked up using @klass. This will not invoke any constructors,
4484 * so the consumer of this routine has to invoke any constructors on
4485 * its own to initialize the object.
4487 * It returns NULL on failure.
4490 mono_object_new (MonoDomain *domain, MonoClass *klass)
4492 MONO_REQ_GC_UNSAFE_MODE;
4496 vtable = mono_class_vtable (domain, klass);
4499 return mono_object_new_specific (vtable);
4503 * mono_object_new_pinned:
4505 * Same as mono_object_new, but the returned object will be pinned.
4506 * For SGEN, these objects will only be freed at appdomain unload.
4509 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4511 MONO_REQ_GC_UNSAFE_MODE;
4515 vtable = mono_class_vtable (domain, klass);
4520 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4522 return mono_object_new_specific (vtable);
4527 * mono_object_new_specific:
4528 * @vtable: the vtable of the object that we want to create
4530 * Returns: A newly created object with class and domain specified
4534 mono_object_new_specific (MonoVTable *vtable)
4536 MONO_REQ_GC_UNSAFE_MODE;
4540 /* check for is_com_object for COM Interop */
4541 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4544 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4547 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4550 mono_class_init (klass);
4552 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4554 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
4555 vtable->domain->create_proxy_for_type_method = im;
4558 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4560 o = mono_runtime_invoke (im, NULL, pa, NULL);
4561 if (o != NULL) return o;
4564 return mono_object_new_alloc_specific (vtable);
4568 mono_object_new_alloc_specific (MonoVTable *vtable)
4570 MONO_REQ_GC_UNSAFE_MODE;
4572 MonoObject *o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4574 if (G_UNLIKELY (vtable->klass->has_finalize))
4575 mono_object_register_finalizer (o);
4581 mono_object_new_fast (MonoVTable *vtable)
4583 MONO_REQ_GC_UNSAFE_MODE;
4585 return mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4589 * mono_class_get_allocation_ftn:
4591 * @for_box: the object will be used for boxing
4592 * @pass_size_in_words:
4594 * Return the allocation function appropriate for the given class.
4598 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4600 MONO_REQ_GC_NEUTRAL_MODE;
4602 *pass_size_in_words = FALSE;
4604 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4605 return mono_object_new_specific;
4607 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4609 return mono_object_new_fast;
4612 * FIXME: This is actually slower than mono_object_new_fast, because
4613 * of the overhead of parameter passing.
4616 *pass_size_in_words = TRUE;
4617 #ifdef GC_REDIRECT_TO_LOCAL
4618 return GC_local_gcj_fast_malloc;
4620 return GC_gcj_fast_malloc;
4625 return mono_object_new_specific;
4629 * mono_object_new_from_token:
4630 * @image: Context where the type_token is hosted
4631 * @token: a token of the type that we want to create
4633 * Returns: A newly created object whose definition is
4634 * looked up using @token in the @image image
4637 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4639 MONO_REQ_GC_UNSAFE_MODE;
4644 klass = mono_class_get_checked (image, token, &error);
4645 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4647 return mono_object_new (domain, klass);
4652 * mono_object_clone:
4653 * @obj: the object to clone
4655 * Returns: A newly created object who is a shallow copy of @obj
4658 mono_object_clone (MonoObject *obj)
4660 MONO_REQ_GC_UNSAFE_MODE;
4663 int size = obj->vtable->klass->instance_size;
4665 if (obj->vtable->klass->rank)
4666 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4668 o = mono_gc_alloc_obj (obj->vtable, size);
4670 /* If the object doesn't contain references this will do a simple memmove. */
4671 mono_gc_wbarrier_object_copy (o, obj);
4673 if (obj->vtable->klass->has_finalize)
4674 mono_object_register_finalizer (o);
4679 * mono_array_full_copy:
4680 * @src: source array to copy
4681 * @dest: destination array
4683 * Copies the content of one array to another with exactly the same type and size.
4686 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4688 MONO_REQ_GC_UNSAFE_MODE;
4691 MonoClass *klass = src->obj.vtable->klass;
4693 g_assert (klass == dest->obj.vtable->klass);
4695 size = mono_array_length (src);
4696 g_assert (size == mono_array_length (dest));
4697 size *= mono_array_element_size (klass);
4699 if (klass->element_class->valuetype) {
4700 if (klass->element_class->has_references)
4701 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4703 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4705 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4708 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4713 * mono_array_clone_in_domain:
4714 * @domain: the domain in which the array will be cloned into
4715 * @array: the array to clone
4717 * This routine returns a copy of the array that is hosted on the
4718 * specified MonoDomain.
4721 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4723 MONO_REQ_GC_UNSAFE_MODE;
4728 MonoClass *klass = array->obj.vtable->klass;
4730 if (array->bounds == NULL) {
4731 size = mono_array_length (array);
4732 o = mono_array_new_full (domain, klass, &size, NULL);
4734 size *= mono_array_element_size (klass);
4736 if (klass->element_class->valuetype) {
4737 if (klass->element_class->has_references)
4738 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4740 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4742 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4745 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4750 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4751 size = mono_array_element_size (klass);
4752 for (i = 0; i < klass->rank; ++i) {
4753 sizes [i] = array->bounds [i].length;
4754 size *= array->bounds [i].length;
4755 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4757 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4759 if (klass->element_class->valuetype) {
4760 if (klass->element_class->has_references)
4761 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4763 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4765 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4768 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4776 * @array: the array to clone
4778 * Returns: A newly created array who is a shallow copy of @array
4781 mono_array_clone (MonoArray *array)
4783 MONO_REQ_GC_UNSAFE_MODE;
4785 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4788 /* helper macros to check for overflow when calculating the size of arrays */
4789 #ifdef MONO_BIG_ARRAYS
4790 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4791 #define MYGUINT_MAX MYGUINT64_MAX
4792 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4793 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4794 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4795 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4796 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4798 #define MYGUINT32_MAX 4294967295U
4799 #define MYGUINT_MAX MYGUINT32_MAX
4800 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4801 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4802 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4803 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4804 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4808 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4810 MONO_REQ_GC_NEUTRAL_MODE;
4814 byte_len = mono_array_element_size (klass);
4815 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4818 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
4820 byte_len += MONO_SIZEOF_MONO_ARRAY;
4828 * mono_array_new_full:
4829 * @domain: domain where the object is created
4830 * @array_class: array class
4831 * @lengths: lengths for each dimension in the array
4832 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4834 * This routine creates a new array objects with the given dimensions,
4835 * lower bounds and type.
4838 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4840 MONO_REQ_GC_UNSAFE_MODE;
4842 uintptr_t byte_len = 0, len, bounds_size;
4845 MonoArrayBounds *bounds;
4849 if (!array_class->inited)
4850 mono_class_init (array_class);
4854 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4855 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4857 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4861 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4863 for (i = 0; i < array_class->rank; ++i) {
4864 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4866 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4867 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4872 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4873 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4877 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4878 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4879 byte_len = (byte_len + 3) & ~3;
4880 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4881 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4882 byte_len += bounds_size;
4885 * Following three lines almost taken from mono_object_new ():
4886 * they need to be kept in sync.
4888 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4890 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4892 o = mono_gc_alloc_vector (vtable, byte_len, len);
4893 array = (MonoArray*)o;
4895 bounds = array->bounds;
4898 for (i = 0; i < array_class->rank; ++i) {
4899 bounds [i].length = lengths [i];
4901 bounds [i].lower_bound = lower_bounds [i];
4910 * @domain: domain where the object is created
4911 * @eclass: element class
4912 * @n: number of array elements
4914 * This routine creates a new szarray with @n elements of type @eclass.
4917 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4919 MONO_REQ_GC_UNSAFE_MODE;
4923 ac = mono_array_class_get (eclass, 1);
4926 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4930 * mono_array_new_specific:
4931 * @vtable: a vtable in the appropriate domain for an initialized class
4932 * @n: number of array elements
4934 * This routine is a fast alternative to mono_array_new() for code which
4935 * can be sure about the domain it operates in.
4938 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4940 MONO_REQ_GC_UNSAFE_MODE;
4946 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4951 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4952 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4955 o = mono_gc_alloc_vector (vtable, byte_len, n);
4962 * mono_string_new_utf16:
4963 * @text: a pointer to an utf16 string
4964 * @len: the length of the string
4966 * Returns: A newly created string object which contains @text.
4969 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4971 MONO_REQ_GC_UNSAFE_MODE;
4975 s = mono_string_new_size (domain, len);
4976 g_assert (s != NULL);
4978 memcpy (mono_string_chars (s), text, len * 2);
4984 * mono_string_new_utf32:
4985 * @text: a pointer to an utf32 string
4986 * @len: the length of the string
4988 * Returns: A newly created string object which contains @text.
4991 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4993 MONO_REQ_GC_UNSAFE_MODE;
4996 mono_unichar2 *utf16_output = NULL;
4997 gint32 utf16_len = 0;
4998 GError *error = NULL;
4999 glong items_written;
5001 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
5004 g_error_free (error);
5006 while (utf16_output [utf16_len]) utf16_len++;
5008 s = mono_string_new_size (domain, utf16_len);
5009 g_assert (s != NULL);
5011 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5013 g_free (utf16_output);
5019 * mono_string_new_size:
5020 * @text: a pointer to an utf16 string
5021 * @len: the length of the string
5023 * Returns: A newly created string object of @len
5026 mono_string_new_size (MonoDomain *domain, gint32 len)
5028 MONO_REQ_GC_UNSAFE_MODE;
5034 /* check for overflow */
5035 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
5036 mono_gc_out_of_memory (-1);
5038 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5039 g_assert (size > 0);
5041 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5044 s = mono_gc_alloc_string (vtable, size, len);
5050 * mono_string_new_len:
5051 * @text: a pointer to an utf8 string
5052 * @length: number of bytes in @text to consider
5054 * Returns: A newly created string object which contains @text.
5057 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5059 MONO_REQ_GC_UNSAFE_MODE;
5061 GError *error = NULL;
5062 MonoString *o = NULL;
5064 glong items_written;
5066 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5069 o = mono_string_new_utf16 (domain, ut, items_written);
5071 g_error_free (error);
5080 * @text: a pointer to an utf8 string
5082 * Returns: A newly created string object which contains @text.
5085 mono_string_new (MonoDomain *domain, const char *text)
5087 MONO_REQ_GC_UNSAFE_MODE;
5089 GError *error = NULL;
5090 MonoString *o = NULL;
5092 glong items_written;
5097 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5100 o = mono_string_new_utf16 (domain, ut, items_written);
5102 g_error_free (error);
5105 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5110 MonoString *o = NULL;
5112 if (!g_utf8_validate (text, -1, &end))
5115 len = g_utf8_strlen (text, -1);
5116 o = mono_string_new_size (domain, len);
5117 str = mono_string_chars (o);
5119 while (text < end) {
5120 *str++ = g_utf8_get_char (text);
5121 text = g_utf8_next_char (text);
5128 * mono_string_new_wrapper:
5129 * @text: pointer to utf8 characters.
5131 * Helper function to create a string object from @text in the current domain.
5134 mono_string_new_wrapper (const char *text)
5136 MONO_REQ_GC_UNSAFE_MODE;
5138 MonoDomain *domain = mono_domain_get ();
5141 return mono_string_new (domain, text);
5148 * @class: the class of the value
5149 * @value: a pointer to the unboxed data
5151 * Returns: A newly created object which contains @value.
5154 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5156 MONO_REQ_GC_UNSAFE_MODE;
5162 g_assert (klass->valuetype);
5163 if (mono_class_is_nullable (klass))
5164 return mono_nullable_box (value, klass);
5166 vtable = mono_class_vtable (domain, klass);
5169 size = mono_class_instance_size (klass);
5170 res = mono_object_new_alloc_specific (vtable);
5172 size = size - sizeof (MonoObject);
5175 g_assert (size == mono_class_value_size (klass, NULL));
5176 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5178 #if NO_UNALIGNED_ACCESS
5179 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5183 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5186 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5189 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5192 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5195 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5199 if (klass->has_finalize)
5200 mono_object_register_finalizer (res);
5206 * @dest: destination pointer
5207 * @src: source pointer
5208 * @klass: a valuetype class
5210 * Copy a valuetype from @src to @dest. This function must be used
5211 * when @klass contains references fields.
5214 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5216 MONO_REQ_GC_UNSAFE_MODE;
5218 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5222 * mono_value_copy_array:
5223 * @dest: destination array
5224 * @dest_idx: index in the @dest array
5225 * @src: source pointer
5226 * @count: number of items
5228 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5229 * This function must be used when @klass contains references fields.
5230 * Overlap is handled.
5233 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5235 MONO_REQ_GC_UNSAFE_MODE;
5237 int size = mono_array_element_size (dest->obj.vtable->klass);
5238 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5239 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5240 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5244 * mono_object_get_domain:
5245 * @obj: object to query
5247 * Returns: the MonoDomain where the object is hosted
5250 mono_object_get_domain (MonoObject *obj)
5252 MONO_REQ_GC_UNSAFE_MODE;
5254 return mono_object_domain (obj);
5258 * mono_object_get_class:
5259 * @obj: object to query
5261 * Returns: the MonOClass of the object.
5264 mono_object_get_class (MonoObject *obj)
5266 MONO_REQ_GC_UNSAFE_MODE;
5268 return mono_object_class (obj);
5271 * mono_object_get_size:
5272 * @o: object to query
5274 * Returns: the size, in bytes, of @o
5277 mono_object_get_size (MonoObject* o)
5279 MONO_REQ_GC_UNSAFE_MODE;
5281 MonoClass* klass = mono_object_class (o);
5282 if (klass == mono_defaults.string_class) {
5283 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5284 } else if (o->vtable->rank) {
5285 MonoArray *array = (MonoArray*)o;
5286 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5287 if (array->bounds) {
5290 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5294 return mono_class_instance_size (klass);
5299 * mono_object_unbox:
5300 * @obj: object to unbox
5302 * Returns: a pointer to the start of the valuetype boxed in this
5305 * This method will assert if the object passed is not a valuetype.
5308 mono_object_unbox (MonoObject *obj)
5310 MONO_REQ_GC_UNSAFE_MODE;
5312 /* add assert for valuetypes? */
5313 g_assert (obj->vtable->klass->valuetype);
5314 return ((char*)obj) + sizeof (MonoObject);
5318 * mono_object_isinst:
5320 * @klass: a pointer to a class
5322 * Returns: @obj if @obj is derived from @klass
5325 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5327 MONO_REQ_GC_UNSAFE_MODE;
5330 mono_class_init (klass);
5332 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5333 return mono_object_isinst_mbyref (obj, klass);
5338 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5342 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5344 MONO_REQ_GC_UNSAFE_MODE;
5353 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5354 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5358 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5359 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5362 MonoClass *oklass = vt->klass;
5363 if (mono_class_is_transparent_proxy (oklass))
5364 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5366 mono_class_setup_supertypes (klass);
5367 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5370 #ifndef DISABLE_REMOTING
5371 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5373 MonoDomain *domain = mono_domain_get ();
5375 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5376 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5377 MonoMethod *im = NULL;
5380 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5382 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5383 im = mono_object_get_virtual_method (rp, im);
5386 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5389 res = mono_runtime_invoke (im, rp, pa, NULL);
5391 if (*(MonoBoolean *) mono_object_unbox(res)) {
5392 /* Update the vtable of the remote type, so it can safely cast to this new type */
5393 mono_upgrade_remote_class (domain, obj, klass);
5397 #endif /* DISABLE_REMOTING */
5402 * mono_object_castclass_mbyref:
5404 * @klass: a pointer to a class
5406 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5409 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5411 MONO_REQ_GC_UNSAFE_MODE;
5413 if (!obj) return NULL;
5414 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5416 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5418 "InvalidCastException"));
5423 MonoDomain *orig_domain;
5429 str_lookup (MonoDomain *domain, gpointer user_data)
5431 MONO_REQ_GC_UNSAFE_MODE;
5433 LDStrInfo *info = user_data;
5434 if (info->res || domain == info->orig_domain)
5436 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5442 mono_string_get_pinned (MonoString *str)
5444 MONO_REQ_GC_UNSAFE_MODE;
5448 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5449 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5451 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5452 news->length = mono_string_length (str);
5458 #define mono_string_get_pinned(str) (str)
5462 mono_string_is_interned_lookup (MonoString *str, int insert)
5464 MONO_REQ_GC_UNSAFE_MODE;
5466 MonoGHashTable *ldstr_table;
5467 MonoString *s, *res;
5470 domain = ((MonoObject *)str)->vtable->domain;
5471 ldstr_table = domain->ldstr_table;
5473 res = mono_g_hash_table_lookup (ldstr_table, str);
5479 /* Allocate outside the lock */
5481 s = mono_string_get_pinned (str);
5484 res = mono_g_hash_table_lookup (ldstr_table, str);
5489 mono_g_hash_table_insert (ldstr_table, s, s);
5494 LDStrInfo ldstr_info;
5495 ldstr_info.orig_domain = domain;
5496 ldstr_info.ins = str;
5497 ldstr_info.res = NULL;
5499 mono_domain_foreach (str_lookup, &ldstr_info);
5500 if (ldstr_info.res) {
5502 * the string was already interned in some other domain:
5503 * intern it in the current one as well.
5505 mono_g_hash_table_insert (ldstr_table, str, str);
5515 * mono_string_is_interned:
5516 * @o: String to probe
5518 * Returns whether the string has been interned.
5521 mono_string_is_interned (MonoString *o)
5523 MONO_REQ_GC_UNSAFE_MODE;
5525 return mono_string_is_interned_lookup (o, FALSE);
5529 * mono_string_intern:
5530 * @o: String to intern
5532 * Interns the string passed.
5533 * Returns: The interned string.
5536 mono_string_intern (MonoString *str)
5538 MONO_REQ_GC_UNSAFE_MODE;
5540 return mono_string_is_interned_lookup (str, TRUE);
5545 * @domain: the domain where the string will be used.
5546 * @image: a metadata context
5547 * @idx: index into the user string table.
5549 * Implementation for the ldstr opcode.
5550 * Returns: a loaded string from the @image/@idx combination.
5553 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5555 MONO_REQ_GC_UNSAFE_MODE;
5557 if (image->dynamic) {
5558 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5561 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5562 return NULL; /*FIXME we should probably be raising an exception here*/
5563 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5568 * mono_ldstr_metadata_sig
5569 * @domain: the domain for the string
5570 * @sig: the signature of a metadata string
5572 * Returns: a MonoString for a string stored in the metadata
5575 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5577 MONO_REQ_GC_UNSAFE_MODE;
5579 const char *str = sig;
5580 MonoString *o, *interned;
5583 len2 = mono_metadata_decode_blob_size (str, &str);
5586 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5587 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5590 guint16 *p2 = (guint16*)mono_string_chars (o);
5591 for (i = 0; i < len2; ++i) {
5592 *p2 = GUINT16_FROM_LE (*p2);
5598 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5601 return interned; /* o will get garbage collected */
5603 o = mono_string_get_pinned (o);
5606 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5608 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5618 * mono_string_to_utf8:
5619 * @s: a System.String
5621 * Returns the UTF8 representation for @s.
5622 * The resulting buffer needs to be freed with mono_free().
5624 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5627 mono_string_to_utf8 (MonoString *s)
5629 MONO_REQ_GC_UNSAFE_MODE;
5632 char *result = mono_string_to_utf8_checked (s, &error);
5634 if (!mono_error_ok (&error))
5635 mono_error_raise_exception (&error);
5640 * mono_string_to_utf8_checked:
5641 * @s: a System.String
5642 * @error: a MonoError.
5644 * Converts a MonoString to its UTF8 representation. May fail; check
5645 * @error to determine whether the conversion was successful.
5646 * The resulting buffer should be freed with mono_free().
5649 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5651 MONO_REQ_GC_UNSAFE_MODE;
5655 GError *gerror = NULL;
5657 mono_error_init (error);
5663 return g_strdup ("");
5665 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5667 mono_error_set_argument (error, "string", "%s", gerror->message);
5668 g_error_free (gerror);
5671 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5672 if (s->length > written) {
5673 /* allocate the total length and copy the part of the string that has been converted */
5674 char *as2 = g_malloc0 (s->length);
5675 memcpy (as2, as, written);
5684 * mono_string_to_utf8_ignore:
5687 * Converts a MonoString to its UTF8 representation. Will ignore
5688 * invalid surrogate pairs.
5689 * The resulting buffer should be freed with mono_free().
5693 mono_string_to_utf8_ignore (MonoString *s)
5695 MONO_REQ_GC_UNSAFE_MODE;
5704 return g_strdup ("");
5706 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5708 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5709 if (s->length > written) {
5710 /* allocate the total length and copy the part of the string that has been converted */
5711 char *as2 = g_malloc0 (s->length);
5712 memcpy (as2, as, written);
5721 * mono_string_to_utf8_image_ignore:
5722 * @s: a System.String
5724 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5727 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5729 MONO_REQ_GC_UNSAFE_MODE;
5731 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5735 * mono_string_to_utf8_mp_ignore:
5736 * @s: a System.String
5738 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5741 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5743 MONO_REQ_GC_UNSAFE_MODE;
5745 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5750 * mono_string_to_utf16:
5753 * Return an null-terminated array of the utf-16 chars
5754 * contained in @s. The result must be freed with g_free().
5755 * This is a temporary helper until our string implementation
5756 * is reworked to always include the null terminating char.
5759 mono_string_to_utf16 (MonoString *s)
5761 MONO_REQ_GC_UNSAFE_MODE;
5768 as = g_malloc ((s->length * 2) + 2);
5769 as [(s->length * 2)] = '\0';
5770 as [(s->length * 2) + 1] = '\0';
5773 return (gunichar2 *)(as);
5776 memcpy (as, mono_string_chars(s), s->length * 2);
5777 return (gunichar2 *)(as);
5781 * mono_string_to_utf32:
5784 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5785 * contained in @s. The result must be freed with g_free().
5788 mono_string_to_utf32 (MonoString *s)
5790 MONO_REQ_GC_UNSAFE_MODE;
5792 mono_unichar4 *utf32_output = NULL;
5793 GError *error = NULL;
5794 glong items_written;
5799 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5802 g_error_free (error);
5804 return utf32_output;
5808 * mono_string_from_utf16:
5809 * @data: the UTF16 string (LPWSTR) to convert
5811 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5813 * Returns: a MonoString.
5816 mono_string_from_utf16 (gunichar2 *data)
5818 MONO_REQ_GC_UNSAFE_MODE;
5820 MonoDomain *domain = mono_domain_get ();
5826 while (data [len]) len++;
5828 return mono_string_new_utf16 (domain, data, len);
5832 * mono_string_from_utf32:
5833 * @data: the UTF32 string (LPWSTR) to convert
5835 * Converts a UTF32 (UCS-4)to a MonoString.
5837 * Returns: a MonoString.
5840 mono_string_from_utf32 (mono_unichar4 *data)
5842 MONO_REQ_GC_UNSAFE_MODE;
5844 MonoString* result = NULL;
5845 mono_unichar2 *utf16_output = NULL;
5846 GError *error = NULL;
5847 glong items_written;
5853 while (data [len]) len++;
5855 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5858 g_error_free (error);
5860 result = mono_string_from_utf16 (utf16_output);
5861 g_free (utf16_output);
5866 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5868 MONO_REQ_GC_UNSAFE_MODE;
5875 r = mono_string_to_utf8_ignore (s);
5877 r = mono_string_to_utf8_checked (s, error);
5878 if (!mono_error_ok (error))
5885 len = strlen (r) + 1;
5887 mp_s = mono_mempool_alloc (mp, len);
5889 mp_s = mono_image_alloc (image, len);
5891 memcpy (mp_s, r, len);
5899 * mono_string_to_utf8_image:
5900 * @s: a System.String
5902 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5905 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5907 MONO_REQ_GC_UNSAFE_MODE;
5909 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5913 * mono_string_to_utf8_mp:
5914 * @s: a System.String
5916 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5919 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5921 MONO_REQ_GC_UNSAFE_MODE;
5923 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5927 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5930 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5932 eh_callbacks = *cbs;
5935 MonoRuntimeExceptionHandlingCallbacks *
5936 mono_get_eh_callbacks (void)
5938 return &eh_callbacks;
5942 * mono_raise_exception:
5943 * @ex: exception object
5945 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5948 mono_raise_exception (MonoException *ex)
5950 MONO_REQ_GC_UNSAFE_MODE;
5953 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5954 * that will cause gcc to omit the function epilog, causing problems when
5955 * the JIT tries to walk the stack, since the return address on the stack
5956 * will point into the next function in the executable, not this one.
5958 eh_callbacks.mono_raise_exception (ex);
5962 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5964 MONO_REQ_GC_UNSAFE_MODE;
5966 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5970 * mono_wait_handle_new:
5971 * @domain: Domain where the object will be created
5972 * @handle: Handle for the wait handle
5974 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5977 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5979 MONO_REQ_GC_UNSAFE_MODE;
5981 MonoWaitHandle *res;
5982 gpointer params [1];
5983 static MonoMethod *handle_set;
5985 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5987 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5989 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5991 params [0] = &handle;
5992 mono_runtime_invoke (handle_set, res, params, NULL);
5998 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6000 MONO_REQ_GC_UNSAFE_MODE;
6002 static MonoClassField *f_os_handle;
6003 static MonoClassField *f_safe_handle;
6005 if (!f_os_handle && !f_safe_handle) {
6006 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6007 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6012 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6016 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6023 mono_runtime_capture_context (MonoDomain *domain)
6025 MONO_REQ_GC_UNSAFE_MODE;
6027 RuntimeInvokeFunction runtime_invoke;
6029 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6030 MonoMethod *method = mono_get_context_capture_method ();
6031 MonoMethod *wrapper;
6034 wrapper = mono_marshal_get_runtime_invoke (method, FALSE, FALSE);
6035 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6036 domain->capture_context_method = mono_compile_method (method);
6039 runtime_invoke = domain->capture_context_runtime_invoke;
6041 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6044 * mono_async_result_new:
6045 * @domain:domain where the object will be created.
6046 * @handle: wait handle.
6047 * @state: state to pass to AsyncResult
6048 * @data: C closure data.
6050 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6051 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6055 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6057 MONO_REQ_GC_UNSAFE_MODE;
6059 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6060 MonoObject *context = mono_runtime_capture_context (domain);
6061 /* we must capture the execution context from the original thread */
6063 MONO_OBJECT_SETREF (res, execution_context, context);
6064 /* note: result may be null if the flow is suppressed */
6068 MONO_OBJECT_SETREF (res, object_data, object_data);
6069 MONO_OBJECT_SETREF (res, async_state, state);
6071 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6073 res->sync_completed = FALSE;
6074 res->completed = FALSE;
6080 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6082 MONO_REQ_GC_UNSAFE_MODE;
6088 g_assert (ares->async_delegate);
6090 ac = (MonoAsyncCall*) ares->object_data;
6092 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6094 gpointer wait_event = NULL;
6096 ac->msg->exc = NULL;
6097 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6098 MONO_OBJECT_SETREF (ac, res, res);
6100 mono_monitor_enter ((MonoObject*) ares);
6101 ares->completed = 1;
6103 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6104 mono_monitor_exit ((MonoObject*) ares);
6106 if (wait_event != NULL)
6107 SetEvent (wait_event);
6109 if (ac->cb_method) {
6110 /* we swallow the excepton as it is the behavior on .NET */
6111 MonoObject *exc = NULL;
6112 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6114 mono_unhandled_exception (exc);
6122 mono_message_init (MonoDomain *domain,
6123 MonoMethodMessage *this_obj,
6124 MonoReflectionMethod *method,
6125 MonoArray *out_args)
6127 MONO_REQ_GC_UNSAFE_MODE;
6129 static MonoClass *object_array_klass;
6130 static MonoClass *byte_array_klass;
6131 static MonoClass *string_array_klass;
6132 MonoMethodSignature *sig = mono_method_signature (method->method);
6138 if (!object_array_klass) {
6141 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6143 byte_array_klass = klass;
6145 klass = mono_array_class_get (mono_defaults.string_class, 1);
6147 string_array_klass = klass;
6149 klass = mono_array_class_get (mono_defaults.object_class, 1);
6152 mono_atomic_store_release (&object_array_klass, klass);
6155 MONO_OBJECT_SETREF (this_obj, method, method);
6157 MONO_OBJECT_SETREF (this_obj, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6158 MONO_OBJECT_SETREF (this_obj, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6159 this_obj->async_result = NULL;
6160 this_obj->call_type = CallType_Sync;
6162 names = g_new (char *, sig->param_count);
6163 mono_method_get_param_names (method->method, (const char **) names);
6164 MONO_OBJECT_SETREF (this_obj, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6166 for (i = 0; i < sig->param_count; i++) {
6167 name = mono_string_new (domain, names [i]);
6168 mono_array_setref (this_obj->names, i, name);
6172 for (i = 0, j = 0; i < sig->param_count; i++) {
6173 if (sig->params [i]->byref) {
6175 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6176 mono_array_setref (this_obj->args, i, arg);
6180 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6184 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6187 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6191 #ifndef DISABLE_REMOTING
6193 * mono_remoting_invoke:
6194 * @real_proxy: pointer to a RealProxy object
6195 * @msg: The MonoMethodMessage to execute
6196 * @exc: used to store exceptions
6197 * @out_args: used to store output arguments
6199 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6200 * IMessage interface and it is not trivial to extract results from there. So
6201 * we call an helper method PrivateInvoke instead of calling
6202 * RealProxy::Invoke() directly.
6204 * Returns: the result object.
6207 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6208 MonoObject **exc, MonoArray **out_args)
6210 MONO_REQ_GC_UNSAFE_MODE;
6212 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6215 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6218 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6220 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6221 real_proxy->vtable->domain->private_invoke_method = im;
6224 pa [0] = real_proxy;
6229 return mono_runtime_invoke (im, NULL, pa, exc);
6234 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6235 MonoObject **exc, MonoArray **out_args)
6237 MONO_REQ_GC_UNSAFE_MODE;
6239 static MonoClass *object_array_klass;
6242 MonoMethodSignature *sig;
6244 int i, j, outarg_count = 0;
6246 #ifndef DISABLE_REMOTING
6247 if (target && mono_object_is_transparent_proxy (target)) {
6248 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6249 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6250 target = tp->rp->unwrapped_server;
6252 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6257 domain = mono_domain_get ();
6258 method = msg->method->method;
6259 sig = mono_method_signature (method);
6261 for (i = 0; i < sig->param_count; i++) {
6262 if (sig->params [i]->byref)
6266 if (!object_array_klass) {
6269 klass = mono_array_class_get (mono_defaults.object_class, 1);
6272 mono_memory_barrier ();
6273 object_array_klass = klass;
6276 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count));
6279 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6281 for (i = 0, j = 0; i < sig->param_count; i++) {
6282 if (sig->params [i]->byref) {
6284 arg = mono_array_get (msg->args, gpointer, i);
6285 mono_array_setref (*out_args, j, arg);
6294 * mono_object_to_string:
6296 * @exc: Any exception thrown by ToString (). May be NULL.
6298 * Returns: the result of calling ToString () on an object.
6301 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6303 MONO_REQ_GC_UNSAFE_MODE;
6305 static MonoMethod *to_string = NULL;
6312 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6314 method = mono_object_get_virtual_method (obj, to_string);
6316 // Unbox value type if needed
6317 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6318 target = mono_object_unbox (obj);
6321 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6325 * mono_print_unhandled_exception:
6326 * @exc: The exception
6328 * Prints the unhandled exception.
6331 mono_print_unhandled_exception (MonoObject *exc)
6333 MONO_REQ_GC_UNSAFE_MODE;
6336 char *message = (char*)"";
6337 gboolean free_message = FALSE;
6340 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6341 message = g_strdup ("OutOfMemoryException");
6342 free_message = TRUE;
6343 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6344 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6345 free_message = TRUE;
6348 if (((MonoException*)exc)->native_trace_ips) {
6349 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6350 free_message = TRUE;
6352 MonoObject *other_exc = NULL;
6353 str = mono_object_to_string (exc, &other_exc);
6355 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6356 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6358 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6359 original_backtrace, nested_backtrace);
6361 g_free (original_backtrace);
6362 g_free (nested_backtrace);
6363 free_message = TRUE;
6365 message = mono_string_to_utf8_checked (str, &error);
6366 if (!mono_error_ok (&error)) {
6367 mono_error_cleanup (&error);
6368 message = (char *) "";
6370 free_message = TRUE;
6377 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6378 * exc->vtable->klass->name, message);
6380 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6387 * mono_delegate_ctor:
6388 * @this: pointer to an uninitialized delegate object
6389 * @target: target object
6390 * @addr: pointer to native code
6393 * Initialize a delegate and sets a specific method, not the one
6394 * associated with addr. This is useful when sharing generic code.
6395 * In that case addr will most probably not be associated with the
6396 * correct instantiation of the method.
6399 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6401 MONO_REQ_GC_UNSAFE_MODE;
6403 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6405 g_assert (this_obj);
6408 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6411 delegate->method = method;
6413 mono_stats.delegate_creations++;
6415 #ifndef DISABLE_REMOTING
6416 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6418 method = mono_marshal_get_remoting_invoke (method);
6419 delegate->method_ptr = mono_compile_method (method);
6420 MONO_OBJECT_SETREF (delegate, target, target);
6424 delegate->method_ptr = addr;
6425 MONO_OBJECT_SETREF (delegate, target, target);
6428 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6432 * mono_delegate_ctor:
6433 * @this: pointer to an uninitialized delegate object
6434 * @target: target object
6435 * @addr: pointer to native code
6437 * This is used to initialize a delegate.
6440 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6442 MONO_REQ_GC_UNSAFE_MODE;
6444 MonoDomain *domain = mono_domain_get ();
6446 MonoMethod *method = NULL;
6450 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6452 if (!ji && domain != mono_get_root_domain ())
6453 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6455 method = mono_jit_info_get_method (ji);
6456 g_assert (!method->klass->generic_container);
6459 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6463 * mono_method_call_message_new:
6464 * @method: method to encapsulate
6465 * @params: parameters to the method
6466 * @invoke: optional, delegate invoke.
6467 * @cb: async callback delegate.
6468 * @state: state passed to the async callback.
6470 * Translates arguments pointers into a MonoMethodMessage.
6473 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6474 MonoDelegate **cb, MonoObject **state)
6476 MONO_REQ_GC_UNSAFE_MODE;
6478 MonoDomain *domain = mono_domain_get ();
6479 MonoMethodSignature *sig = mono_method_signature (method);
6480 MonoMethodMessage *msg;
6483 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6486 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6487 count = sig->param_count - 2;
6489 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6490 count = sig->param_count;
6493 for (i = 0; i < count; i++) {
6498 if (sig->params [i]->byref)
6499 vpos = *((gpointer *)params [i]);
6503 klass = mono_class_from_mono_type (sig->params [i]);
6505 if (klass->valuetype)
6506 arg = mono_value_box (domain, klass, vpos);
6508 arg = *((MonoObject **)vpos);
6510 mono_array_setref (msg->args, i, arg);
6513 if (cb != NULL && state != NULL) {
6514 *cb = *((MonoDelegate **)params [i]);
6516 *state = *((MonoObject **)params [i]);
6523 * mono_method_return_message_restore:
6525 * Restore results from message based processing back to arguments pointers
6528 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6530 MONO_REQ_GC_UNSAFE_MODE;
6532 MonoMethodSignature *sig = mono_method_signature (method);
6533 int i, j, type, size, out_len;
6535 if (out_args == NULL)
6537 out_len = mono_array_length (out_args);
6541 for (i = 0, j = 0; i < sig->param_count; i++) {
6542 MonoType *pt = sig->params [i];
6547 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6549 arg = mono_array_get (out_args, gpointer, j);
6552 g_assert (type != MONO_TYPE_VOID);
6554 if (MONO_TYPE_IS_REFERENCE (pt)) {
6555 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6558 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6559 size = mono_class_value_size (klass, NULL);
6560 if (klass->has_references)
6561 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6563 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6565 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6566 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6575 #ifndef DISABLE_REMOTING
6578 * mono_load_remote_field:
6579 * @this: pointer to an object
6580 * @klass: klass of the object containing @field
6581 * @field: the field to load
6582 * @res: a storage to store the result
6584 * This method is called by the runtime on attempts to load fields of
6585 * transparent proxy objects. @this points to such TP, @klass is the class of
6586 * the object containing @field. @res is a storage location which can be
6587 * used to store the result.
6589 * Returns: an address pointing to the value of field.
6592 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6594 MONO_REQ_GC_UNSAFE_MODE;
6596 static MonoMethod *getter = NULL;
6597 MonoDomain *domain = mono_domain_get ();
6598 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6599 MonoClass *field_class;
6600 MonoMethodMessage *msg;
6601 MonoArray *out_args;
6605 g_assert (mono_object_is_transparent_proxy (this_obj));
6606 g_assert (res != NULL);
6608 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6609 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6614 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6616 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6619 field_class = mono_class_from_mono_type (field->type);
6621 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6622 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6623 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6625 full_name = mono_type_get_full_name (klass);
6626 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6627 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6630 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6632 if (exc) mono_raise_exception ((MonoException *)exc);
6634 if (mono_array_length (out_args) == 0)
6637 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6639 if (field_class->valuetype) {
6640 return ((char *)*res) + sizeof (MonoObject);
6646 * mono_load_remote_field_new:
6651 * Missing documentation.
6654 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6656 MONO_REQ_GC_UNSAFE_MODE;
6658 static MonoMethod *getter = NULL;
6659 MonoDomain *domain = mono_domain_get ();
6660 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6661 MonoClass *field_class;
6662 MonoMethodMessage *msg;
6663 MonoArray *out_args;
6664 MonoObject *exc, *res;
6667 g_assert (mono_object_is_transparent_proxy (this_obj));
6669 field_class = mono_class_from_mono_type (field->type);
6671 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6673 if (field_class->valuetype) {
6674 res = mono_object_new (domain, field_class);
6675 val = ((gchar *) res) + sizeof (MonoObject);
6679 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6684 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6686 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6689 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6690 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6692 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6694 full_name = mono_type_get_full_name (klass);
6695 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6696 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6699 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6701 if (exc) mono_raise_exception ((MonoException *)exc);
6703 if (mono_array_length (out_args) == 0)
6706 res = mono_array_get (out_args, MonoObject *, 0);
6712 * mono_store_remote_field:
6713 * @this_obj: pointer to an object
6714 * @klass: klass of the object containing @field
6715 * @field: the field to load
6716 * @val: the value/object to store
6718 * This method is called by the runtime on attempts to store fields of
6719 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6720 * the object containing @field. @val is the new value to store in @field.
6723 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6725 MONO_REQ_GC_UNSAFE_MODE;
6727 static MonoMethod *setter = NULL;
6728 MonoDomain *domain = mono_domain_get ();
6729 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6730 MonoClass *field_class;
6731 MonoMethodMessage *msg;
6732 MonoArray *out_args;
6737 g_assert (mono_object_is_transparent_proxy (this_obj));
6739 field_class = mono_class_from_mono_type (field->type);
6741 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6742 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6743 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6748 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6750 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6753 if (field_class->valuetype)
6754 arg = mono_value_box (domain, field_class, val);
6756 arg = *((MonoObject **)val);
6759 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6760 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6762 full_name = mono_type_get_full_name (klass);
6763 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6764 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6765 mono_array_setref (msg->args, 2, arg);
6768 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6770 if (exc) mono_raise_exception ((MonoException *)exc);
6774 * mono_store_remote_field_new:
6780 * Missing documentation
6783 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6785 MONO_REQ_GC_UNSAFE_MODE;
6787 static MonoMethod *setter = NULL;
6788 MonoDomain *domain = mono_domain_get ();
6789 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6790 MonoClass *field_class;
6791 MonoMethodMessage *msg;
6792 MonoArray *out_args;
6796 g_assert (mono_object_is_transparent_proxy (this_obj));
6798 field_class = mono_class_from_mono_type (field->type);
6800 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6801 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6802 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6807 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6809 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6812 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6813 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6815 full_name = mono_type_get_full_name (klass);
6816 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6817 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6818 mono_array_setref (msg->args, 2, arg);
6821 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6823 if (exc) mono_raise_exception ((MonoException *)exc);
6828 * mono_create_ftnptr:
6830 * Given a function address, create a function descriptor for it.
6831 * This is only needed on some platforms.
6834 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6836 return callbacks.create_ftnptr (domain, addr);
6840 * mono_get_addr_from_ftnptr:
6842 * Given a pointer to a function descriptor, return the function address.
6843 * This is only needed on some platforms.
6846 mono_get_addr_from_ftnptr (gpointer descr)
6848 return callbacks.get_addr_from_ftnptr (descr);
6852 * mono_string_chars:
6855 * Returns a pointer to the UCS16 characters stored in the MonoString
6858 mono_string_chars (MonoString *s)
6860 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
6866 * mono_string_length:
6869 * Returns the lenght in characters of the string
6872 mono_string_length (MonoString *s)
6874 MONO_REQ_GC_UNSAFE_MODE;
6880 * mono_array_length:
6881 * @array: a MonoArray*
6883 * Returns the total number of elements in the array. This works for
6884 * both vectors and multidimensional arrays.
6887 mono_array_length (MonoArray *array)
6889 MONO_REQ_GC_UNSAFE_MODE;
6891 return array->max_length;
6895 * mono_array_addr_with_size:
6896 * @array: a MonoArray*
6897 * @size: size of the array elements
6898 * @idx: index into the array
6900 * Returns the address of the @idx element in the array.
6903 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6905 MONO_REQ_GC_UNSAFE_MODE;
6907 return ((char*)(array)->vector) + size * idx;
6912 mono_glist_to_array (GList *list, MonoClass *eclass)
6914 MonoDomain *domain = mono_domain_get ();
6921 len = g_list_length (list);
6922 res = mono_array_new (domain, eclass, len);
6924 for (i = 0; list; list = list->next, i++)
6925 mono_array_set (res, gpointer, i, list->data);