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/exception-internals.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internals.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/reflection-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include "cominterop.h"
52 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
55 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
58 free_main_args (void);
61 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
63 /* Class lazy loading functions */
64 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
65 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
66 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
67 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
68 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
71 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
72 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
73 static mono_mutex_t ldstr_section;
76 mono_runtime_object_init (MonoObject *this_obj)
78 MONO_REQ_GC_UNSAFE_MODE;
81 MonoMethod *method = NULL;
82 MonoClass *klass = this_obj->vtable->klass;
84 method = mono_class_get_method_from_name (klass, ".ctor", 0);
86 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
88 if (method->klass->valuetype)
89 this_obj = (MonoObject *)mono_object_unbox (this_obj);
91 mono_runtime_invoke_checked (method, this_obj, NULL, &error);
92 mono_error_raise_exception (&error); /* FIXME don't raise here */
95 /* The pseudo algorithm for type initialization from the spec
96 Note it doesn't say anything about domains - only threads.
98 2. If the type is initialized you are done.
99 2.1. If the type is not yet initialized, try to take an
101 2.2. If successful, record this thread as responsible for
102 initializing the type and proceed to step 2.3.
103 2.2.1. If not, see whether this thread or any thread
104 waiting for this thread to complete already holds the lock.
105 2.2.2. If so, return since blocking would create a deadlock. This thread
106 will now see an incompletely initialized state for the type,
107 but no deadlock will arise.
108 2.2.3 If not, block until the type is initialized then return.
109 2.3 Initialize the parent type and then all interfaces implemented
111 2.4 Execute the type initialization code for this type.
112 2.5 Mark the type as initialized, release the initialization lock,
113 awaken any threads waiting for this type to be initialized,
120 MonoNativeThreadId initializing_tid;
121 guint32 waiting_count;
123 MonoCoopMutex initialization_section;
124 } TypeInitializationLock;
126 /* for locking access to type_initialization_hash and blocked_thread_hash */
127 static MonoCoopMutex type_initialization_section;
130 mono_type_initialization_lock (void)
132 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
133 mono_coop_mutex_lock (&type_initialization_section);
137 mono_type_initialization_unlock (void)
139 mono_coop_mutex_unlock (&type_initialization_section);
143 mono_type_init_lock (TypeInitializationLock *lock)
145 MONO_REQ_GC_NEUTRAL_MODE;
147 mono_coop_mutex_lock (&lock->initialization_section);
151 mono_type_init_unlock (TypeInitializationLock *lock)
153 mono_coop_mutex_unlock (&lock->initialization_section);
156 /* from vtable to lock */
157 static GHashTable *type_initialization_hash;
159 /* from thread id to thread id being waited on */
160 static GHashTable *blocked_thread_hash;
163 static MonoThread *main_thread;
165 /* Functions supplied by the runtime */
166 static MonoRuntimeCallbacks callbacks;
169 * mono_thread_set_main:
170 * @thread: thread to set as the main thread
172 * This function can be used to instruct the runtime to treat @thread
173 * as the main thread, ie, the thread that would normally execute the Main()
174 * method. This basically means that at the end of @thread, the runtime will
175 * wait for the existing foreground threads to quit and other such details.
178 mono_thread_set_main (MonoThread *thread)
180 MONO_REQ_GC_UNSAFE_MODE;
182 static gboolean registered = FALSE;
185 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
189 main_thread = thread;
193 mono_thread_get_main (void)
195 MONO_REQ_GC_UNSAFE_MODE;
201 mono_type_initialization_init (void)
203 mono_coop_mutex_init_recursive (&type_initialization_section);
204 type_initialization_hash = g_hash_table_new (NULL, NULL);
205 blocked_thread_hash = g_hash_table_new (NULL, NULL);
206 mono_os_mutex_init_recursive (&ldstr_section);
210 mono_type_initialization_cleanup (void)
213 /* This is causing race conditions with
214 * mono_release_type_locks
216 mono_coop_mutex_destroy (&type_initialization_section);
217 g_hash_table_destroy (type_initialization_hash);
218 type_initialization_hash = NULL;
220 mono_os_mutex_destroy (&ldstr_section);
221 g_hash_table_destroy (blocked_thread_hash);
222 blocked_thread_hash = NULL;
228 * get_type_init_exception_for_vtable:
230 * Return the stored type initialization exception for VTABLE.
232 static MonoException*
233 get_type_init_exception_for_vtable (MonoVTable *vtable)
235 MONO_REQ_GC_UNSAFE_MODE;
238 MonoDomain *domain = vtable->domain;
239 MonoClass *klass = vtable->klass;
243 if (!vtable->init_failed)
244 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
247 * If the initializing thread was rudely aborted, the exception is not stored
251 mono_domain_lock (domain);
252 if (domain->type_init_exception_hash)
253 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
254 mono_domain_unlock (domain);
257 if (klass->name_space && *klass->name_space)
258 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
260 full_name = g_strdup (klass->name);
261 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
263 return_val_if_nok (&error, NULL);
270 * mono_runtime_class_init:
271 * @vtable: vtable that needs to be initialized
273 * This routine calls the class constructor for @vtable.
276 mono_runtime_class_init (MonoVTable *vtable)
278 MONO_REQ_GC_UNSAFE_MODE;
281 mono_runtime_class_init_full (vtable, &error);
282 mono_error_assert_ok (&error);
286 * mono_runtime_class_init_full:
287 * @vtable that neeeds to be initialized
288 * @error set on error
290 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
294 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
296 MONO_REQ_GC_UNSAFE_MODE;
298 MonoMethod *method = NULL;
301 MonoDomain *domain = vtable->domain;
302 TypeInitializationLock *lock;
303 MonoNativeThreadId tid;
304 int do_initialization = 0;
305 MonoDomain *last_domain = NULL;
307 mono_error_init (error);
309 if (vtable->initialized)
312 klass = vtable->klass;
314 if (!klass->image->checked_module_cctor) {
315 mono_image_check_for_module_cctor (klass->image);
316 if (klass->image->has_module_cctor) {
317 MonoClass *module_klass;
318 MonoVTable *module_vtable;
320 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
325 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
328 if (!mono_runtime_class_init_full (module_vtable, error))
332 method = mono_class_get_cctor (klass);
334 vtable->initialized = 1;
338 tid = mono_native_thread_id_get ();
340 mono_type_initialization_lock ();
341 /* double check... */
342 if (vtable->initialized) {
343 mono_type_initialization_unlock ();
346 if (vtable->init_failed) {
347 mono_type_initialization_unlock ();
349 /* The type initialization already failed once, rethrow the same exception */
350 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
353 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
355 /* This thread will get to do the initialization */
356 if (mono_domain_get () != domain) {
357 /* Transfer into the target domain */
358 last_domain = mono_domain_get ();
359 if (!mono_domain_set (domain, FALSE)) {
360 vtable->initialized = 1;
361 mono_type_initialization_unlock ();
362 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
366 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
367 mono_coop_mutex_init_recursive (&lock->initialization_section);
368 lock->initializing_tid = tid;
369 lock->waiting_count = 1;
371 /* grab the vtable lock while this thread still owns type_initialization_section */
372 /* This is why type_initialization_lock needs to enter blocking mode */
373 mono_type_init_lock (lock);
374 g_hash_table_insert (type_initialization_hash, vtable, lock);
375 do_initialization = 1;
378 TypeInitializationLock *pending_lock;
380 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
381 mono_type_initialization_unlock ();
384 /* see if the thread doing the initialization is already blocked on this thread */
385 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
386 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
387 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
388 if (!pending_lock->done) {
389 mono_type_initialization_unlock ();
392 /* the thread doing the initialization is blocked on this thread,
393 but on a lock that has already been freed. It just hasn't got
398 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
400 ++lock->waiting_count;
401 /* record the fact that we are waiting on the initializing thread */
402 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
404 mono_type_initialization_unlock ();
406 if (do_initialization) {
407 MonoException *exc = NULL;
408 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
409 if (exc != NULL && mono_error_ok (error)) {
410 mono_error_set_exception_instance (error, exc);
413 /* If the initialization failed, mark the class as unusable. */
414 /* Avoid infinite loops */
415 if (!(mono_error_ok(error) ||
416 (klass->image == mono_defaults.corlib &&
417 !strcmp (klass->name_space, "System") &&
418 !strcmp (klass->name, "TypeInitializationException")))) {
419 vtable->init_failed = 1;
421 if (klass->name_space && *klass->name_space)
422 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
424 full_name = g_strdup (klass->name);
426 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
428 return_val_if_nok (error, FALSE);
430 mono_error_set_exception_instance (error, exc_to_throw);
432 MonoException *exc_to_store = mono_error_convert_to_exception (error);
433 /* What we really want to do here is clone the error object and store one copy in the
434 * domain's exception hash and use the other one to error out here. */
435 mono_error_set_exception_instance (error, exc_to_store);
437 * Store the exception object so it could be thrown on subsequent
440 mono_domain_lock (domain);
441 if (!domain->type_init_exception_hash)
442 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");
443 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
444 mono_domain_unlock (domain);
448 mono_domain_set (last_domain, TRUE);
450 mono_type_init_unlock (lock);
452 /* this just blocks until the initializing thread is done */
453 mono_type_init_lock (lock);
454 mono_type_init_unlock (lock);
457 mono_type_initialization_lock ();
458 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
459 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
460 --lock->waiting_count;
461 if (lock->waiting_count == 0) {
462 mono_coop_mutex_destroy (&lock->initialization_section);
463 g_hash_table_remove (type_initialization_hash, vtable);
466 mono_memory_barrier ();
467 if (!vtable->init_failed)
468 vtable->initialized = 1;
469 mono_type_initialization_unlock ();
471 if (vtable->init_failed) {
472 /* Either we were the initializing thread or we waited for the initialization */
473 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
480 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
482 MONO_REQ_GC_NEUTRAL_MODE;
484 MonoVTable *vtable = (MonoVTable*)key;
486 TypeInitializationLock *lock = (TypeInitializationLock*) value;
487 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
490 * Have to set this since it cannot be set by the normal code in
491 * mono_runtime_class_init (). In this case, the exception object is not stored,
492 * and get_type_init_exception_for_class () needs to be aware of this.
494 vtable->init_failed = 1;
495 mono_type_init_unlock (lock);
496 --lock->waiting_count;
497 if (lock->waiting_count == 0) {
498 mono_coop_mutex_destroy (&lock->initialization_section);
507 mono_release_type_locks (MonoInternalThread *thread)
509 MONO_REQ_GC_UNSAFE_MODE;
511 mono_type_initialization_lock ();
512 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
513 mono_type_initialization_unlock ();
517 default_trampoline (MonoMethod *method)
523 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
525 g_assert_not_reached ();
530 #ifndef DISABLE_REMOTING
533 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
535 g_error ("remoting not installed");
539 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
543 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
545 g_assert_not_reached ();
549 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
550 static MonoImtThunkBuilder imt_thunk_builder;
551 static gboolean always_build_imt_thunks;
553 #if (MONO_IMT_SIZE > 32)
554 #error "MONO_IMT_SIZE cannot be larger than 32"
558 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
560 memcpy (&callbacks, cbs, sizeof (*cbs));
563 MonoRuntimeCallbacks*
564 mono_get_runtime_callbacks (void)
569 #ifndef DISABLE_REMOTING
571 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
573 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
578 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
580 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
584 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
585 imt_thunk_builder = func;
589 mono_set_always_build_imt_thunks (gboolean value)
591 always_build_imt_thunks = value;
595 * mono_compile_method:
596 * @method: The method to compile.
598 * This JIT-compiles the method, and returns the pointer to the native code
602 mono_compile_method (MonoMethod *method)
607 MONO_REQ_GC_NEUTRAL_MODE
609 if (!callbacks.compile_method) {
610 g_error ("compile method called on uninitialized runtime");
613 res = callbacks.compile_method (method, &error);
614 if (!mono_error_ok (&error))
615 mono_error_raise_exception (&error);
620 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
625 MONO_REQ_GC_NEUTRAL_MODE;
627 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, &error);
628 if (!mono_error_ok (&error))
629 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
634 mono_runtime_create_delegate_trampoline (MonoClass *klass)
636 MONO_REQ_GC_NEUTRAL_MODE
638 return arch_create_delegate_trampoline (mono_domain_get (), klass);
641 static MonoFreeMethodFunc default_mono_free_method = NULL;
644 * mono_install_free_method:
645 * @func: pointer to the MonoFreeMethodFunc used to release a method
647 * This is an internal VM routine, it is used for the engines to
648 * register a handler to release the resources associated with a method.
650 * Methods are freed when no more references to the delegate that holds
654 mono_install_free_method (MonoFreeMethodFunc func)
656 default_mono_free_method = func;
660 * mono_runtime_free_method:
661 * @domain; domain where the method is hosted
662 * @method: method to release
664 * This routine is invoked to free the resources associated with
665 * a method that has been JIT compiled. This is used to discard
666 * methods that were used only temporarily (for example, used in marshalling)
670 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
672 MONO_REQ_GC_NEUTRAL_MODE
674 if (default_mono_free_method != NULL)
675 default_mono_free_method (domain, method);
677 mono_method_clear_object (domain, method);
679 mono_free_method (method);
683 * The vtables in the root appdomain are assumed to be reachable by other
684 * roots, and we don't use typed allocation in the other domains.
687 /* The sync block is no longer a GC pointer */
688 #define GC_HEADER_BITMAP (0)
690 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
693 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
695 MONO_REQ_GC_NEUTRAL_MODE;
697 MonoClassField *field;
703 max_size = mono_class_data_size (klass) / sizeof (gpointer);
705 max_size = klass->instance_size / sizeof (gpointer);
706 if (max_size > size) {
707 g_assert (offset <= 0);
708 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
713 /*An Ephemeron cannot be marked by sgen*/
714 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
716 memset (bitmap, 0, size / 8);
721 for (p = klass; p != NULL; p = p->parent) {
722 gpointer iter = NULL;
723 while ((field = mono_class_get_fields (p, &iter))) {
727 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
729 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
732 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
735 /* FIXME: should not happen, flag as type load error */
736 if (field->type->byref)
739 if (static_fields && field->offset == -1)
743 pos = field->offset / sizeof (gpointer);
746 type = mono_type_get_underlying_type (field->type);
747 switch (type->type) {
750 case MONO_TYPE_FNPTR:
752 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
757 if (klass->image != mono_defaults.corlib)
760 case MONO_TYPE_STRING:
761 case MONO_TYPE_SZARRAY:
762 case MONO_TYPE_CLASS:
763 case MONO_TYPE_OBJECT:
764 case MONO_TYPE_ARRAY:
765 g_assert ((field->offset % sizeof(gpointer)) == 0);
767 g_assert (pos < size || pos <= max_size);
768 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
769 *max_set = MAX (*max_set, pos);
771 case MONO_TYPE_GENERICINST:
772 if (!mono_type_generic_inst_is_valuetype (type)) {
773 g_assert ((field->offset % sizeof(gpointer)) == 0);
775 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
776 *max_set = MAX (*max_set, pos);
781 case MONO_TYPE_VALUETYPE: {
782 MonoClass *fclass = mono_class_from_mono_type (field->type);
783 if (fclass->has_references) {
784 /* remove the object header */
785 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
799 case MONO_TYPE_BOOLEAN:
803 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
814 * mono_class_compute_bitmap:
816 * Mono internal function to compute a bitmap of reference fields in a class.
819 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
821 MONO_REQ_GC_NEUTRAL_MODE;
823 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
828 * similar to the above, but sets the bits in the bitmap for any non-ref field
829 * and ignores static fields
832 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
834 MonoClassField *field;
839 max_size = class->instance_size / sizeof (gpointer);
840 if (max_size >= size) {
841 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
844 for (p = class; p != NULL; p = p->parent) {
845 gpointer iter = NULL;
846 while ((field = mono_class_get_fields (p, &iter))) {
849 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
851 /* FIXME: should not happen, flag as type load error */
852 if (field->type->byref)
855 pos = field->offset / sizeof (gpointer);
858 type = mono_type_get_underlying_type (field->type);
859 switch (type->type) {
860 #if SIZEOF_VOID_P == 8
864 case MONO_TYPE_FNPTR:
869 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
870 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
871 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
874 #if SIZEOF_VOID_P == 4
878 case MONO_TYPE_FNPTR:
883 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
884 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
885 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
891 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
892 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
893 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
896 case MONO_TYPE_BOOLEAN:
899 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
901 case MONO_TYPE_STRING:
902 case MONO_TYPE_SZARRAY:
903 case MONO_TYPE_CLASS:
904 case MONO_TYPE_OBJECT:
905 case MONO_TYPE_ARRAY:
907 case MONO_TYPE_GENERICINST:
908 if (!mono_type_generic_inst_is_valuetype (type)) {
913 case MONO_TYPE_VALUETYPE: {
914 MonoClass *fclass = mono_class_from_mono_type (field->type);
915 /* remove the object header */
916 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
920 g_assert_not_reached ();
929 * mono_class_insecure_overlapping:
930 * check if a class with explicit layout has references and non-references
931 * fields overlapping.
933 * Returns: TRUE if it is insecure to load the type.
936 mono_class_insecure_overlapping (MonoClass *klass)
940 gsize default_bitmap [4] = {0};
942 gsize default_nrbitmap [4] = {0};
943 int i, insecure = FALSE;
946 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
947 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
949 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
950 int idx = i % (sizeof (bitmap [0]) * 8);
951 if (bitmap [idx] & nrbitmap [idx]) {
956 if (bitmap != default_bitmap)
958 if (nrbitmap != default_nrbitmap)
961 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
969 ves_icall_string_alloc (int length)
972 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
973 mono_error_raise_exception (&error);
979 mono_class_compute_gc_descriptor (MonoClass *klass)
981 MONO_REQ_GC_NEUTRAL_MODE;
985 gsize default_bitmap [4] = {0};
986 static gboolean gcj_inited = FALSE;
991 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
992 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
995 mono_loader_unlock ();
999 mono_class_init (klass);
1001 if (klass->gc_descr_inited)
1004 klass->gc_descr_inited = TRUE;
1005 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1007 bitmap = default_bitmap;
1008 if (klass == mono_defaults.string_class) {
1009 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1010 } else if (klass->rank) {
1011 mono_class_compute_gc_descriptor (klass->element_class);
1012 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1014 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1015 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1016 class->name_space, class->name);*/
1018 /* remove the object header */
1019 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1020 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));
1021 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1022 class->name_space, class->name);*/
1023 if (bitmap != default_bitmap)
1027 /*static int count = 0;
1030 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1031 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1033 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1034 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1036 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1037 if (bitmap != default_bitmap)
1043 * field_is_special_static:
1044 * @fklass: The MonoClass to look up.
1045 * @field: The MonoClassField describing the field.
1047 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1048 * SPECIAL_STATIC_NONE otherwise.
1051 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1053 MONO_REQ_GC_NEUTRAL_MODE;
1056 MonoCustomAttrInfo *ainfo;
1058 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1059 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1062 for (i = 0; i < ainfo->num_attrs; ++i) {
1063 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1064 if (klass->image == mono_defaults.corlib) {
1065 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1066 mono_custom_attrs_free (ainfo);
1067 return SPECIAL_STATIC_THREAD;
1069 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1070 mono_custom_attrs_free (ainfo);
1071 return SPECIAL_STATIC_CONTEXT;
1075 mono_custom_attrs_free (ainfo);
1076 return SPECIAL_STATIC_NONE;
1079 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1080 #define mix(a,b,c) { \
1081 a -= c; a ^= rot(c, 4); c += b; \
1082 b -= a; b ^= rot(a, 6); a += c; \
1083 c -= b; c ^= rot(b, 8); b += a; \
1084 a -= c; a ^= rot(c,16); c += b; \
1085 b -= a; b ^= rot(a,19); a += c; \
1086 c -= b; c ^= rot(b, 4); b += a; \
1088 #define final(a,b,c) { \
1089 c ^= b; c -= rot(b,14); \
1090 a ^= c; a -= rot(c,11); \
1091 b ^= a; b -= rot(a,25); \
1092 c ^= b; c -= rot(b,16); \
1093 a ^= c; a -= rot(c,4); \
1094 b ^= a; b -= rot(a,14); \
1095 c ^= b; c -= rot(b,24); \
1099 * mono_method_get_imt_slot:
1101 * The IMT slot is embedded into AOTed code, so this must return the same value
1102 * for the same method across all executions. This means:
1103 * - pointers shouldn't be used as hash values.
1104 * - mono_metadata_str_hash () should be used for hashing strings.
1107 mono_method_get_imt_slot (MonoMethod *method)
1109 MONO_REQ_GC_NEUTRAL_MODE;
1111 MonoMethodSignature *sig;
1113 guint32 *hashes_start, *hashes;
1117 /* This can be used to stress tests the collision code */
1121 * We do this to simplify generic sharing. It will hurt
1122 * performance in cases where a class implements two different
1123 * instantiations of the same generic interface.
1124 * The code in build_imt_slots () depends on this.
1126 if (method->is_inflated)
1127 method = ((MonoMethodInflated*)method)->declaring;
1129 sig = mono_method_signature (method);
1130 hashes_count = sig->param_count + 4;
1131 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1132 hashes = hashes_start;
1134 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1135 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1136 method->klass->name_space, method->klass->name, method->name);
1139 /* Initialize hashes */
1140 hashes [0] = mono_metadata_str_hash (method->klass->name);
1141 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1142 hashes [2] = mono_metadata_str_hash (method->name);
1143 hashes [3] = mono_metadata_type_hash (sig->ret);
1144 for (i = 0; i < sig->param_count; i++) {
1145 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1148 /* Setup internal state */
1149 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1151 /* Handle most of the hashes */
1152 while (hashes_count > 3) {
1161 /* Handle the last 3 hashes (all the case statements fall through) */
1162 switch (hashes_count) {
1163 case 3 : c += hashes [2];
1164 case 2 : b += hashes [1];
1165 case 1 : a += hashes [0];
1167 case 0: /* nothing left to add */
1171 free (hashes_start);
1172 /* Report the result */
1173 return c % MONO_IMT_SIZE;
1182 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1183 MONO_REQ_GC_NEUTRAL_MODE;
1185 guint32 imt_slot = mono_method_get_imt_slot (method);
1186 MonoImtBuilderEntry *entry;
1188 if (slot_num >= 0 && imt_slot != slot_num) {
1189 /* we build just a single imt slot and this is not it */
1193 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1194 entry->key = method;
1195 entry->value.vtable_slot = vtable_slot;
1196 entry->next = imt_builder [imt_slot];
1197 if (imt_builder [imt_slot] != NULL) {
1198 entry->children = imt_builder [imt_slot]->children + 1;
1199 if (entry->children == 1) {
1200 mono_stats.imt_slots_with_collisions++;
1201 *imt_collisions_bitmap |= (1 << imt_slot);
1204 entry->children = 0;
1205 mono_stats.imt_used_slots++;
1207 imt_builder [imt_slot] = entry;
1210 char *method_name = mono_method_full_name (method, TRUE);
1211 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1212 method, method_name, imt_slot, vtable_slot, entry->children);
1213 g_free (method_name);
1220 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1222 MonoMethod *method = e->key;
1223 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1227 method->klass->name_space,
1228 method->klass->name,
1231 printf (" * %s: NULL\n", message);
1237 compare_imt_builder_entries (const void *p1, const void *p2) {
1238 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1239 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1241 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1245 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1247 MONO_REQ_GC_NEUTRAL_MODE;
1249 int count = end - start;
1250 int chunk_start = out_array->len;
1253 for (i = start; i < end; ++i) {
1254 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1255 item->key = sorted_array [i]->key;
1256 item->value = sorted_array [i]->value;
1257 item->has_target_code = sorted_array [i]->has_target_code;
1258 item->is_equals = TRUE;
1260 item->check_target_idx = out_array->len + 1;
1262 item->check_target_idx = 0;
1263 g_ptr_array_add (out_array, item);
1266 int middle = start + count / 2;
1267 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1269 item->key = sorted_array [middle]->key;
1270 item->is_equals = FALSE;
1271 g_ptr_array_add (out_array, item);
1272 imt_emit_ir (sorted_array, start, middle, out_array);
1273 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1279 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1280 MONO_REQ_GC_NEUTRAL_MODE;
1282 int number_of_entries = entries->children + 1;
1283 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1284 GPtrArray *result = g_ptr_array_new ();
1285 MonoImtBuilderEntry *current_entry;
1288 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1289 sorted_array [i] = current_entry;
1291 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1293 /*for (i = 0; i < number_of_entries; i++) {
1294 print_imt_entry (" sorted array:", sorted_array [i], i);
1297 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1299 free (sorted_array);
1304 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1306 MONO_REQ_GC_NEUTRAL_MODE;
1308 if (imt_builder_entry != NULL) {
1309 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1310 /* No collision, return the vtable slot contents */
1311 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1313 /* Collision, build the thunk */
1314 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1317 result = imt_thunk_builder (vtable, domain,
1318 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1319 for (i = 0; i < imt_ir->len; ++i)
1320 g_free (g_ptr_array_index (imt_ir, i));
1321 g_ptr_array_free (imt_ir, TRUE);
1333 static MonoImtBuilderEntry*
1334 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1337 * LOCKING: requires the loader and domain locks.
1341 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1343 MONO_REQ_GC_NEUTRAL_MODE;
1347 guint32 imt_collisions_bitmap = 0;
1348 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1349 int method_count = 0;
1350 gboolean record_method_count_for_max_collisions = FALSE;
1351 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1354 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1356 for (i = 0; i < klass->interface_offsets_count; ++i) {
1357 MonoClass *iface = klass->interfaces_packed [i];
1358 int interface_offset = klass->interface_offsets_packed [i];
1359 int method_slot_in_interface, vt_slot;
1361 if (mono_class_has_variant_generic_params (iface))
1362 has_variant_iface = TRUE;
1364 mono_class_setup_methods (iface);
1365 vt_slot = interface_offset;
1366 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1369 if (slot_num >= 0 && iface->is_inflated) {
1371 * The imt slot of the method is the same as for its declaring method,
1372 * see the comment in mono_method_get_imt_slot (), so we can
1373 * avoid inflating methods which will be discarded by
1374 * add_imt_builder_entry anyway.
1376 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1377 if (mono_method_get_imt_slot (method) != slot_num) {
1382 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1383 if (method->is_generic) {
1384 has_generic_virtual = TRUE;
1389 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1390 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1395 if (extra_interfaces) {
1396 int interface_offset = klass->vtable_size;
1398 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1399 MonoClass* iface = (MonoClass *)list_item->data;
1400 int method_slot_in_interface;
1401 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1402 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1404 if (method->is_generic)
1405 has_generic_virtual = TRUE;
1406 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1408 interface_offset += iface->method.count;
1411 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1412 /* overwrite the imt slot only if we're building all the entries or if
1413 * we're building this specific one
1415 if (slot_num < 0 || i == slot_num) {
1416 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1419 if (imt_builder [i]) {
1420 MonoImtBuilderEntry *entry;
1422 /* Link entries with imt_builder [i] */
1423 for (entry = entries; entry->next; entry = entry->next) {
1425 MonoMethod *method = (MonoMethod*)entry->key;
1426 char *method_name = mono_method_full_name (method, TRUE);
1427 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1428 g_free (method_name);
1431 entry->next = imt_builder [i];
1432 entries->children += imt_builder [i]->children + 1;
1434 imt_builder [i] = entries;
1437 if (has_generic_virtual || has_variant_iface) {
1439 * There might be collisions later when the the thunk is expanded.
1441 imt_collisions_bitmap |= (1 << i);
1444 * The IMT thunk might be called with an instance of one of the
1445 * generic virtual methods, so has to fallback to the IMT trampoline.
1447 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1449 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1452 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1456 if (imt_builder [i] != NULL) {
1457 int methods_in_slot = imt_builder [i]->children + 1;
1458 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1459 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1460 record_method_count_for_max_collisions = TRUE;
1462 method_count += methods_in_slot;
1466 mono_stats.imt_number_of_methods += method_count;
1467 if (record_method_count_for_max_collisions) {
1468 mono_stats.imt_method_count_when_max_collisions = method_count;
1471 for (i = 0; i < MONO_IMT_SIZE; i++) {
1472 MonoImtBuilderEntry* entry = imt_builder [i];
1473 while (entry != NULL) {
1474 MonoImtBuilderEntry* next = entry->next;
1480 /* we OR the bitmap since we may build just a single imt slot at a time */
1481 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1485 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1486 MONO_REQ_GC_NEUTRAL_MODE;
1488 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1492 * mono_vtable_build_imt_slot:
1493 * @vtable: virtual object table struct
1494 * @imt_slot: slot in the IMT table
1496 * Fill the given @imt_slot in the IMT table of @vtable with
1497 * a trampoline or a thunk for the case of collisions.
1498 * This is part of the internal mono API.
1500 * LOCKING: Take the domain lock.
1503 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1505 MONO_REQ_GC_NEUTRAL_MODE;
1507 gpointer *imt = (gpointer*)vtable;
1508 imt -= MONO_IMT_SIZE;
1509 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1511 /* no support for extra interfaces: the proxy objects will need
1512 * to build the complete IMT
1513 * Update and heck needs to ahppen inside the proper domain lock, as all
1514 * the changes made to a MonoVTable.
1516 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1517 mono_domain_lock (vtable->domain);
1518 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1519 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1520 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1521 mono_domain_unlock (vtable->domain);
1522 mono_loader_unlock ();
1527 * The first two free list entries both belong to the wait list: The
1528 * first entry is the pointer to the head of the list and the second
1529 * entry points to the last element. That way appending and removing
1530 * the first element are both O(1) operations.
1532 #ifdef MONO_SMALL_CONFIG
1533 #define NUM_FREE_LISTS 6
1535 #define NUM_FREE_LISTS 12
1537 #define FIRST_FREE_LIST_SIZE 64
1538 #define MAX_WAIT_LENGTH 50
1539 #define THUNK_THRESHOLD 10
1542 * LOCKING: The domain lock must be held.
1545 init_thunk_free_lists (MonoDomain *domain)
1547 MONO_REQ_GC_NEUTRAL_MODE;
1549 if (domain->thunk_free_lists)
1551 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1555 list_index_for_size (int item_size)
1558 int size = FIRST_FREE_LIST_SIZE;
1560 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1569 * mono_method_alloc_generic_virtual_thunk:
1571 * @size: size in bytes
1573 * Allocs size bytes to be used for the code of a generic virtual
1574 * thunk. It's either allocated from the domain's code manager or
1575 * reused from a previously invalidated piece.
1577 * LOCKING: The domain lock must be held.
1580 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1582 MONO_REQ_GC_NEUTRAL_MODE;
1584 static gboolean inited = FALSE;
1585 static int generic_virtual_thunks_size = 0;
1589 MonoThunkFreeList **l;
1591 init_thunk_free_lists (domain);
1593 size += sizeof (guint32);
1594 if (size < sizeof (MonoThunkFreeList))
1595 size = sizeof (MonoThunkFreeList);
1597 i = list_index_for_size (size);
1598 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1599 if ((*l)->size >= size) {
1600 MonoThunkFreeList *item = *l;
1602 return ((guint32*)item) + 1;
1606 /* no suitable item found - search lists of larger sizes */
1607 while (++i < NUM_FREE_LISTS) {
1608 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1611 g_assert (item->size > size);
1612 domain->thunk_free_lists [i] = item->next;
1613 return ((guint32*)item) + 1;
1616 /* still nothing found - allocate it */
1618 mono_counters_register ("Generic virtual thunk bytes",
1619 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1622 generic_virtual_thunks_size += size;
1624 p = (guint32 *)mono_domain_code_reserve (domain, size);
1627 mono_domain_lock (domain);
1628 if (!domain->generic_virtual_thunks)
1629 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1630 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1631 mono_domain_unlock (domain);
1637 * LOCKING: The domain lock must be held.
1640 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1642 MONO_REQ_GC_NEUTRAL_MODE;
1644 guint32 *p = (guint32 *)code;
1645 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1646 gboolean found = FALSE;
1648 mono_domain_lock (domain);
1649 if (!domain->generic_virtual_thunks)
1650 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1651 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1653 mono_domain_unlock (domain);
1656 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1658 init_thunk_free_lists (domain);
1660 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1661 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1662 int length = item->length;
1665 /* unlink the first item from the wait list */
1666 domain->thunk_free_lists [0] = item->next;
1667 domain->thunk_free_lists [0]->length = length - 1;
1669 i = list_index_for_size (item->size);
1671 /* put it in the free list */
1672 item->next = domain->thunk_free_lists [i];
1673 domain->thunk_free_lists [i] = item;
1677 if (domain->thunk_free_lists [1]) {
1678 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1679 domain->thunk_free_lists [0]->length++;
1681 g_assert (!domain->thunk_free_lists [0]);
1683 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1684 domain->thunk_free_lists [0]->length = 1;
1688 typedef struct _GenericVirtualCase {
1692 struct _GenericVirtualCase *next;
1693 } GenericVirtualCase;
1696 * get_generic_virtual_entries:
1698 * Return IMT entries for the generic virtual method instances and
1699 * variant interface methods for vtable slot
1702 static MonoImtBuilderEntry*
1703 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1705 MONO_REQ_GC_NEUTRAL_MODE;
1707 GenericVirtualCase *list;
1708 MonoImtBuilderEntry *entries;
1710 mono_domain_lock (domain);
1711 if (!domain->generic_virtual_cases)
1712 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1714 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1717 for (; list; list = list->next) {
1718 MonoImtBuilderEntry *entry;
1720 if (list->count < THUNK_THRESHOLD)
1723 entry = g_new0 (MonoImtBuilderEntry, 1);
1724 entry->key = list->method;
1725 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1726 entry->has_target_code = 1;
1728 entry->children = entries->children + 1;
1729 entry->next = entries;
1733 mono_domain_unlock (domain);
1735 /* FIXME: Leaking memory ? */
1740 * mono_method_add_generic_virtual_invocation:
1742 * @vtable_slot: pointer to the vtable slot
1743 * @method: the inflated generic virtual method
1744 * @code: the method's code
1746 * Registers a call via unmanaged code to a generic virtual method
1747 * instantiation or variant interface method. If the number of calls reaches a threshold
1748 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1749 * virtual method thunk.
1752 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1753 gpointer *vtable_slot,
1754 MonoMethod *method, gpointer code)
1756 MONO_REQ_GC_NEUTRAL_MODE;
1758 static gboolean inited = FALSE;
1759 static int num_added = 0;
1761 GenericVirtualCase *gvc, *list;
1762 MonoImtBuilderEntry *entries;
1766 mono_domain_lock (domain);
1767 if (!domain->generic_virtual_cases)
1768 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1770 /* Check whether the case was already added */
1771 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1774 if (gvc->method == method)
1779 /* If not found, make a new one */
1781 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1782 gvc->method = method;
1785 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1787 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1790 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1796 if (++gvc->count == THUNK_THRESHOLD) {
1797 gpointer *old_thunk = (void **)*vtable_slot;
1798 gpointer vtable_trampoline = NULL;
1799 gpointer imt_trampoline = NULL;
1801 if ((gpointer)vtable_slot < (gpointer)vtable) {
1802 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1803 int imt_slot = MONO_IMT_SIZE + displacement;
1805 /* Force the rebuild of the thunk at the next call */
1806 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1807 *vtable_slot = imt_trampoline;
1809 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1811 entries = get_generic_virtual_entries (domain, vtable_slot);
1813 sorted = imt_sort_slot_entries (entries);
1815 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1819 MonoImtBuilderEntry *next = entries->next;
1824 for (i = 0; i < sorted->len; ++i)
1825 g_free (g_ptr_array_index (sorted, i));
1826 g_ptr_array_free (sorted, TRUE);
1829 #ifndef __native_client__
1830 /* We don't re-use any thunks as there is a lot of overhead */
1831 /* to deleting and re-using code in Native Client. */
1832 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1833 invalidate_generic_virtual_thunk (domain, old_thunk);
1837 mono_domain_unlock (domain);
1840 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1843 * mono_class_vtable:
1844 * @domain: the application domain
1845 * @class: the class to initialize
1847 * VTables are domain specific because we create domain specific code, and
1848 * they contain the domain specific static class data.
1849 * On failure, NULL is returned, and class->exception_type is set.
1852 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1855 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1856 mono_error_cleanup (&error);
1861 * mono_class_vtable_full:
1862 * @domain: the application domain
1863 * @class: the class to initialize
1864 * @error set on failure.
1866 * VTables are domain specific because we create domain specific code, and
1867 * they contain the domain specific static class data.
1870 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1872 MONO_REQ_GC_UNSAFE_MODE;
1874 MonoClassRuntimeInfo *runtime_info;
1876 mono_error_init (error);
1880 if (mono_class_has_failure (klass)) {
1881 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1885 /* this check can be inlined in jitted code, too */
1886 runtime_info = klass->runtime_info;
1887 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1888 return runtime_info->domain_vtables [domain->domain_id];
1889 return mono_class_create_runtime_vtable (domain, klass, error);
1893 * mono_class_try_get_vtable:
1894 * @domain: the application domain
1895 * @class: the class to initialize
1897 * This function tries to get the associated vtable from @class if
1898 * it was already created.
1901 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1903 MONO_REQ_GC_NEUTRAL_MODE;
1905 MonoClassRuntimeInfo *runtime_info;
1909 runtime_info = klass->runtime_info;
1910 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1911 return runtime_info->domain_vtables [domain->domain_id];
1916 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1918 MONO_REQ_GC_NEUTRAL_MODE;
1920 size_t alloc_offset;
1923 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1924 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1925 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1927 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1928 g_assert ((imt_table_bytes & 7) == 4);
1935 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1939 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1941 MONO_REQ_GC_UNSAFE_MODE;
1944 MonoClassRuntimeInfo *runtime_info, *old_info;
1945 MonoClassField *field;
1947 int i, vtable_slots;
1948 size_t imt_table_bytes;
1950 guint32 vtable_size, class_size;
1952 gpointer *interface_offsets;
1954 mono_error_init (error);
1956 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1957 mono_domain_lock (domain);
1958 runtime_info = klass->runtime_info;
1959 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1960 mono_domain_unlock (domain);
1961 mono_loader_unlock ();
1962 return runtime_info->domain_vtables [domain->domain_id];
1964 if (!klass->inited || mono_class_has_failure (klass)) {
1965 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1966 mono_domain_unlock (domain);
1967 mono_loader_unlock ();
1968 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1973 /* Array types require that their element type be valid*/
1974 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1975 MonoClass *element_class = klass->element_class;
1976 if (!element_class->inited)
1977 mono_class_init (element_class);
1979 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1980 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1981 mono_class_setup_vtable (element_class);
1983 if (mono_class_has_failure (element_class)) {
1984 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1985 if (!mono_class_has_failure (klass))
1986 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1987 mono_domain_unlock (domain);
1988 mono_loader_unlock ();
1989 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1995 * For some classes, mono_class_init () already computed klass->vtable_size, and
1996 * that is all that is needed because of the vtable trampolines.
1998 if (!klass->vtable_size)
1999 mono_class_setup_vtable (klass);
2001 if (klass->generic_class && !klass->vtable)
2002 mono_class_check_vtable_constraints (klass, NULL);
2004 /* Initialize klass->has_finalize */
2005 mono_class_has_finalizer (klass);
2007 if (mono_class_has_failure (klass)) {
2008 mono_domain_unlock (domain);
2009 mono_loader_unlock ();
2010 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2014 vtable_slots = klass->vtable_size;
2015 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2016 class_size = mono_class_data_size (klass);
2020 if (klass->interface_offsets_count) {
2021 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2022 mono_stats.imt_number_of_tables++;
2023 mono_stats.imt_tables_size += imt_table_bytes;
2025 imt_table_bytes = 0;
2028 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2030 mono_stats.used_class_count++;
2031 mono_stats.class_vtable_size += vtable_size;
2033 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2034 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2035 g_assert (!((gsize)vt & 7));
2038 vt->rank = klass->rank;
2039 vt->domain = domain;
2041 mono_class_compute_gc_descriptor (klass);
2043 * We can't use typed allocation in the non-root domains, since the
2044 * collector needs the GC descriptor stored in the vtable even after
2045 * the mempool containing the vtable is destroyed when the domain is
2046 * unloaded. An alternative might be to allocate vtables in the GC
2047 * heap, but this does not seem to work (it leads to crashes inside
2048 * libgc). If that approach is tried, two gc descriptors need to be
2049 * allocated for each class: one for the root domain, and one for all
2050 * other domains. The second descriptor should contain a bit for the
2051 * vtable field in MonoObject, since we can no longer assume the
2052 * vtable is reachable by other roots after the appdomain is unloaded.
2054 #ifdef HAVE_BOEHM_GC
2055 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2056 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2059 vt->gc_descr = klass->gc_descr;
2061 gc_bits = mono_gc_get_vtable_bits (klass);
2062 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2064 vt->gc_bits = gc_bits;
2067 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2068 if (klass->has_static_refs) {
2069 MonoGCDescriptor statics_gc_descr;
2071 gsize default_bitmap [4] = {0};
2074 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2075 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2076 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2077 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2078 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2079 if (bitmap != default_bitmap)
2082 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2084 vt->has_static_fields = TRUE;
2085 mono_stats.class_static_data_size += class_size;
2089 while ((field = mono_class_get_fields (klass, &iter))) {
2090 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2092 if (mono_field_is_deleted (field))
2094 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2095 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2096 if (special_static != SPECIAL_STATIC_NONE) {
2097 guint32 size, offset;
2099 gsize default_bitmap [4] = {0};
2104 if (mono_type_is_reference (field->type)) {
2105 default_bitmap [0] = 1;
2107 bitmap = default_bitmap;
2108 } else if (mono_type_is_struct (field->type)) {
2109 fclass = mono_class_from_mono_type (field->type);
2110 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2111 numbits = max_set + 1;
2113 default_bitmap [0] = 0;
2115 bitmap = default_bitmap;
2117 size = mono_type_size (field->type, &align);
2118 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2119 if (!domain->special_static_fields)
2120 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2121 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2122 if (bitmap != default_bitmap)
2125 * This marks the field as special static to speed up the
2126 * checks in mono_field_static_get/set_value ().
2132 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2133 MonoClass *fklass = mono_class_from_mono_type (field->type);
2134 const char *data = mono_field_get_data (field);
2136 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2137 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2138 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2141 if (fklass->valuetype) {
2142 memcpy (t, data, mono_class_value_size (fklass, NULL));
2144 /* it's a pointer type: add check */
2145 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2152 vt->max_interface_id = klass->max_interface_id;
2153 vt->interface_bitmap = klass->interface_bitmap;
2155 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2156 // class->name, klass->interface_offsets_count);
2158 /* Initialize vtable */
2159 if (callbacks.get_vtable_trampoline) {
2160 // This also covers the AOT case
2161 for (i = 0; i < klass->vtable_size; ++i) {
2162 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2165 mono_class_setup_vtable (klass);
2167 for (i = 0; i < klass->vtable_size; ++i) {
2170 cm = klass->vtable [i];
2172 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2173 if (!is_ok (error)) {
2174 mono_domain_unlock (domain);
2175 mono_loader_unlock ();
2182 if (imt_table_bytes) {
2183 /* Now that the vtable is full, we can actually fill up the IMT */
2184 for (i = 0; i < MONO_IMT_SIZE; ++i)
2185 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2189 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2190 * re-acquire them and check if another thread has created the vtable in the meantime.
2192 /* Special case System.MonoType to avoid infinite recursion */
2193 if (klass != mono_defaults.monotype_class) {
2194 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2195 if (!is_ok (error)) {
2196 mono_domain_unlock (domain);
2197 mono_loader_unlock ();
2201 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2202 /* This is unregistered in
2203 unregister_vtable_reflection_type() in
2205 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2208 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2210 /* class_vtable_array keeps an array of created vtables
2212 g_ptr_array_add (domain->class_vtable_array, vt);
2213 /* klass->runtime_info is protected by the loader lock, both when
2214 * it it enlarged and when it is stored info.
2218 * Store the vtable in klass->runtime_info.
2219 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2221 mono_memory_barrier ();
2223 old_info = klass->runtime_info;
2224 if (old_info && old_info->max_domain >= domain->domain_id) {
2225 /* someone already created a large enough runtime info */
2226 old_info->domain_vtables [domain->domain_id] = vt;
2228 int new_size = domain->domain_id;
2230 new_size = MAX (new_size, old_info->max_domain);
2232 /* make the new size a power of two */
2234 while (new_size > i)
2237 /* this is a bounded memory retention issue: may want to
2238 * handle it differently when we'll have a rcu-like system.
2240 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2241 runtime_info->max_domain = new_size - 1;
2242 /* copy the stuff from the older info */
2244 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2246 runtime_info->domain_vtables [domain->domain_id] = vt;
2248 mono_memory_barrier ();
2249 klass->runtime_info = runtime_info;
2252 if (klass == mono_defaults.monotype_class) {
2253 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2254 if (!is_ok (error)) {
2255 mono_domain_unlock (domain);
2256 mono_loader_unlock ();
2260 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2261 /* This is unregistered in
2262 unregister_vtable_reflection_type() in
2264 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2267 mono_domain_unlock (domain);
2268 mono_loader_unlock ();
2270 /* make sure the parent is initialized */
2271 /*FIXME shouldn't this fail the current type?*/
2273 mono_class_vtable_full (domain, klass->parent, error);
2278 #ifndef DISABLE_REMOTING
2280 * mono_class_proxy_vtable:
2281 * @domain: the application domain
2282 * @remove_class: the remote class
2284 * Creates a vtable for transparent proxies. It is basically
2285 * a copy of the real vtable of the class wrapped in @remote_class,
2286 * but all function pointers invoke the remoting functions, and
2287 * vtable->klass points to the transparent proxy class, and not to @class.
2290 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2292 MONO_REQ_GC_UNSAFE_MODE;
2295 MonoVTable *vt, *pvt;
2296 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2298 GSList *extra_interfaces = NULL;
2299 MonoClass *klass = remote_class->proxy_class;
2300 gpointer *interface_offsets;
2303 size_t imt_table_bytes;
2305 #ifdef COMPRESSED_INTERFACE_BITMAP
2309 vt = mono_class_vtable (domain, klass);
2310 g_assert (vt); /*FIXME property handle failure*/
2311 max_interface_id = vt->max_interface_id;
2313 /* Calculate vtable space for extra interfaces */
2314 for (j = 0; j < remote_class->interface_count; j++) {
2315 MonoClass* iclass = remote_class->interfaces[j];
2319 /*FIXME test for interfaces with variant generic arguments*/
2320 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2321 continue; /* interface implemented by the class */
2322 if (g_slist_find (extra_interfaces, iclass))
2325 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2327 method_count = mono_class_num_methods (iclass);
2329 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2330 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2332 for (i = 0; i < ifaces->len; ++i) {
2333 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2334 /*FIXME test for interfaces with variant generic arguments*/
2335 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2336 continue; /* interface implemented by the class */
2337 if (g_slist_find (extra_interfaces, ic))
2339 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2340 method_count += mono_class_num_methods (ic);
2342 g_ptr_array_free (ifaces, TRUE);
2345 extra_interface_vtsize += method_count * sizeof (gpointer);
2346 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2349 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2350 mono_stats.imt_number_of_tables++;
2351 mono_stats.imt_tables_size += imt_table_bytes;
2353 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2355 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2357 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2358 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2359 g_assert (!((gsize)pvt & 7));
2361 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2363 pvt->klass = mono_defaults.transparent_proxy_class;
2364 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2365 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2367 /* initialize vtable */
2368 mono_class_setup_vtable (klass);
2369 for (i = 0; i < klass->vtable_size; ++i) {
2372 if ((cm = klass->vtable [i]))
2373 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2375 pvt->vtable [i] = NULL;
2378 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2379 /* create trampolines for abstract methods */
2380 for (k = klass; k; k = k->parent) {
2382 gpointer iter = NULL;
2383 while ((m = mono_class_get_methods (k, &iter)))
2384 if (!pvt->vtable [m->slot])
2385 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2389 pvt->max_interface_id = max_interface_id;
2390 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2391 #ifdef COMPRESSED_INTERFACE_BITMAP
2392 bitmap = (uint8_t *)g_malloc0 (bsize);
2394 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2397 for (i = 0; i < klass->interface_offsets_count; ++i) {
2398 int interface_id = klass->interfaces_packed [i]->interface_id;
2399 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2402 if (extra_interfaces) {
2403 int slot = klass->vtable_size;
2409 /* Create trampolines for the methods of the interfaces */
2410 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2411 interf = (MonoClass *)list_item->data;
2413 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2417 while ((cm = mono_class_get_methods (interf, &iter)))
2418 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2420 slot += mono_class_num_methods (interf);
2424 /* Now that the vtable is full, we can actually fill up the IMT */
2425 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2426 if (extra_interfaces) {
2427 g_slist_free (extra_interfaces);
2430 #ifdef COMPRESSED_INTERFACE_BITMAP
2431 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2432 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2433 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2436 pvt->interface_bitmap = bitmap;
2441 #endif /* DISABLE_REMOTING */
2444 * mono_class_field_is_special_static:
2446 * Returns whether @field is a thread/context static field.
2449 mono_class_field_is_special_static (MonoClassField *field)
2451 MONO_REQ_GC_NEUTRAL_MODE
2453 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2455 if (mono_field_is_deleted (field))
2457 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2458 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2465 * mono_class_field_get_special_static_type:
2466 * @field: The MonoClassField describing the field.
2468 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2469 * SPECIAL_STATIC_NONE otherwise.
2472 mono_class_field_get_special_static_type (MonoClassField *field)
2474 MONO_REQ_GC_NEUTRAL_MODE
2476 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2477 return SPECIAL_STATIC_NONE;
2478 if (mono_field_is_deleted (field))
2479 return SPECIAL_STATIC_NONE;
2480 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2481 return field_is_special_static (field->parent, field);
2482 return SPECIAL_STATIC_NONE;
2486 * mono_class_has_special_static_fields:
2488 * Returns whenever @klass has any thread/context static fields.
2491 mono_class_has_special_static_fields (MonoClass *klass)
2493 MONO_REQ_GC_NEUTRAL_MODE
2495 MonoClassField *field;
2499 while ((field = mono_class_get_fields (klass, &iter))) {
2500 g_assert (field->parent == klass);
2501 if (mono_class_field_is_special_static (field))
2508 #ifndef DISABLE_REMOTING
2510 * create_remote_class_key:
2511 * Creates an array of pointers that can be used as a hash key for a remote class.
2512 * The first element of the array is the number of pointers.
2515 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2517 MONO_REQ_GC_NEUTRAL_MODE;
2522 if (remote_class == NULL) {
2523 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2524 key = (void **)g_malloc (sizeof(gpointer) * 3);
2525 key [0] = GINT_TO_POINTER (2);
2526 key [1] = mono_defaults.marshalbyrefobject_class;
2527 key [2] = extra_class;
2529 key = (void **)g_malloc (sizeof(gpointer) * 2);
2530 key [0] = GINT_TO_POINTER (1);
2531 key [1] = extra_class;
2534 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2535 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2536 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2537 key [1] = remote_class->proxy_class;
2539 // Keep the list of interfaces sorted
2540 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2541 if (extra_class && remote_class->interfaces [i] > extra_class) {
2542 key [j++] = extra_class;
2545 key [j] = remote_class->interfaces [i];
2548 key [j] = extra_class;
2550 // Replace the old class. The interface list is the same
2551 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2552 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2553 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2554 for (i = 0; i < remote_class->interface_count; i++)
2555 key [2 + i] = remote_class->interfaces [i];
2563 * copy_remote_class_key:
2565 * Make a copy of KEY in the domain and return the copy.
2568 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2570 MONO_REQ_GC_NEUTRAL_MODE
2572 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2573 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2575 memcpy (mp_key, key, key_size);
2581 * mono_remote_class:
2582 * @domain: the application domain
2583 * @class_name: name of the remote class
2585 * Creates and initializes a MonoRemoteClass object for a remote type.
2587 * Can raise an exception on failure.
2590 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2592 MONO_REQ_GC_UNSAFE_MODE;
2595 MonoRemoteClass *rc;
2596 gpointer* key, *mp_key;
2599 key = create_remote_class_key (NULL, proxy_class);
2601 mono_domain_lock (domain);
2602 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2606 mono_domain_unlock (domain);
2610 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2611 if (!mono_error_ok (&error)) {
2613 mono_domain_unlock (domain);
2614 mono_error_raise_exception (&error);
2617 mp_key = copy_remote_class_key (domain, key);
2621 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2622 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2623 rc->interface_count = 1;
2624 rc->interfaces [0] = proxy_class;
2625 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2627 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2628 rc->interface_count = 0;
2629 rc->proxy_class = proxy_class;
2632 rc->default_vtable = NULL;
2633 rc->xdomain_vtable = NULL;
2634 rc->proxy_class_name = name;
2635 #ifndef DISABLE_PERFCOUNTERS
2636 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2639 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2641 mono_domain_unlock (domain);
2646 * clone_remote_class:
2647 * Creates a copy of the remote_class, adding the provided class or interface
2649 static MonoRemoteClass*
2650 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2652 MONO_REQ_GC_NEUTRAL_MODE;
2654 MonoRemoteClass *rc;
2655 gpointer* key, *mp_key;
2657 key = create_remote_class_key (remote_class, extra_class);
2658 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2664 mp_key = copy_remote_class_key (domain, key);
2668 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2670 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2671 rc->proxy_class = remote_class->proxy_class;
2672 rc->interface_count = remote_class->interface_count + 1;
2674 // Keep the list of interfaces sorted, since the hash key of
2675 // the remote class depends on this
2676 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2677 if (remote_class->interfaces [i] > extra_class && i == j)
2678 rc->interfaces [j++] = extra_class;
2679 rc->interfaces [j] = remote_class->interfaces [i];
2682 rc->interfaces [j] = extra_class;
2684 // Replace the old class. The interface array is the same
2685 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2686 rc->proxy_class = extra_class;
2687 rc->interface_count = remote_class->interface_count;
2688 if (rc->interface_count > 0)
2689 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2692 rc->default_vtable = NULL;
2693 rc->xdomain_vtable = NULL;
2694 rc->proxy_class_name = remote_class->proxy_class_name;
2696 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2702 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2704 MONO_REQ_GC_UNSAFE_MODE;
2706 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2707 mono_domain_lock (domain);
2708 if (rp->target_domain_id != -1) {
2709 if (remote_class->xdomain_vtable == NULL)
2710 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2711 mono_domain_unlock (domain);
2712 mono_loader_unlock ();
2713 return remote_class->xdomain_vtable;
2715 if (remote_class->default_vtable == NULL) {
2718 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2719 klass = mono_class_from_mono_type (type);
2721 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)))
2722 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2725 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2728 mono_domain_unlock (domain);
2729 mono_loader_unlock ();
2730 return remote_class->default_vtable;
2734 * mono_upgrade_remote_class:
2735 * @domain: the application domain
2736 * @tproxy: the proxy whose remote class has to be upgraded.
2737 * @klass: class to which the remote class can be casted.
2739 * Updates the vtable of the remote class by adding the necessary method slots
2740 * and interface offsets so it can be safely casted to klass. klass can be a
2741 * class or an interface.
2744 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2746 MONO_REQ_GC_UNSAFE_MODE;
2748 MonoTransparentProxy *tproxy;
2749 MonoRemoteClass *remote_class;
2750 gboolean redo_vtable;
2752 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2753 mono_domain_lock (domain);
2755 tproxy = (MonoTransparentProxy*) proxy_object;
2756 remote_class = tproxy->remote_class;
2758 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2761 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2762 if (remote_class->interfaces [i] == klass)
2763 redo_vtable = FALSE;
2766 redo_vtable = (remote_class->proxy_class != klass);
2770 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2771 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2774 mono_domain_unlock (domain);
2775 mono_loader_unlock ();
2777 #endif /* DISABLE_REMOTING */
2781 * mono_object_get_virtual_method:
2782 * @obj: object to operate on.
2785 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2786 * the instance of a callvirt of method.
2789 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2791 MONO_REQ_GC_UNSAFE_MODE;
2794 MonoMethod **vtable;
2795 gboolean is_proxy = FALSE;
2796 MonoMethod *res = NULL;
2798 klass = mono_object_class (obj);
2799 #ifndef DISABLE_REMOTING
2800 if (klass == mono_defaults.transparent_proxy_class) {
2801 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2806 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2809 mono_class_setup_vtable (klass);
2810 vtable = klass->vtable;
2812 if (method->slot == -1) {
2813 /* method->slot might not be set for instances of generic methods */
2814 if (method->is_inflated) {
2815 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2816 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2819 g_assert_not_reached ();
2823 /* check method->slot is a valid index: perform isinstance? */
2824 if (method->slot != -1) {
2825 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2827 gboolean variance_used = FALSE;
2828 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2829 g_assert (iface_offset > 0);
2830 res = vtable [iface_offset + method->slot];
2833 res = vtable [method->slot];
2837 #ifndef DISABLE_REMOTING
2839 /* It may be an interface, abstract class method or generic method */
2840 if (!res || mono_method_signature (res)->generic_param_count)
2843 /* generic methods demand invoke_with_check */
2844 if (mono_method_signature (res)->generic_param_count)
2845 res = mono_marshal_get_remoting_invoke_with_check (res);
2848 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2849 res = mono_cominterop_get_invoke (res);
2852 res = mono_marshal_get_remoting_invoke (res);
2857 if (method->is_inflated) {
2859 /* Have to inflate the result */
2860 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2861 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2871 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2873 MONO_REQ_GC_UNSAFE_MODE;
2875 MonoObject *result = NULL;
2877 g_assert (callbacks.runtime_invoke);
2879 mono_error_init (error);
2881 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2882 mono_profiler_method_start_invoke (method);
2884 MONO_PREPARE_RESET_BLOCKING;
2886 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2888 MONO_FINISH_RESET_BLOCKING;
2890 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2891 mono_profiler_method_end_invoke (method);
2893 if (!mono_error_ok (error))
2900 * mono_runtime_invoke:
2901 * @method: method to invoke
2902 * @obJ: object instance
2903 * @params: arguments to the method
2904 * @exc: exception information.
2906 * Invokes the method represented by @method on the object @obj.
2908 * obj is the 'this' pointer, it should be NULL for static
2909 * methods, a MonoObject* for object instances and a pointer to
2910 * the value type for value types.
2912 * The params array contains the arguments to the method with the
2913 * same convention: MonoObject* pointers for object instances and
2914 * pointers to the value type otherwise.
2916 * From unmanaged code you'll usually use the
2917 * mono_runtime_invoke() variant.
2919 * Note that this function doesn't handle virtual methods for
2920 * you, it will exec the exact method you pass: we still need to
2921 * expose a function to lookup the derived class implementation
2922 * of a virtual method (there are examples of this in the code,
2925 * You can pass NULL as the exc argument if you don't want to
2926 * catch exceptions, otherwise, *exc will be set to the exception
2927 * thrown, if any. if an exception is thrown, you can't use the
2928 * MonoObject* result from the function.
2930 * If the method returns a value type, it is boxed in an object
2934 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2939 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2940 if (*exc == NULL && !mono_error_ok(&error)) {
2941 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2943 mono_error_cleanup (&error);
2945 res = mono_runtime_invoke_checked (method, obj, params, &error);
2946 mono_error_raise_exception (&error);
2952 * mono_runtime_try_invoke:
2953 * @method: method to invoke
2954 * @obJ: object instance
2955 * @params: arguments to the method
2956 * @exc: exception information.
2957 * @error: set on error
2959 * Invokes the method represented by @method on the object @obj.
2961 * obj is the 'this' pointer, it should be NULL for static
2962 * methods, a MonoObject* for object instances and a pointer to
2963 * the value type for value types.
2965 * The params array contains the arguments to the method with the
2966 * same convention: MonoObject* pointers for object instances and
2967 * pointers to the value type otherwise.
2969 * From unmanaged code you'll usually use the
2970 * mono_runtime_invoke() variant.
2972 * Note that this function doesn't handle virtual methods for
2973 * you, it will exec the exact method you pass: we still need to
2974 * expose a function to lookup the derived class implementation
2975 * of a virtual method (there are examples of this in the code,
2978 * For this function, you must not pass NULL as the exc argument if
2979 * you don't want to catch exceptions, use
2980 * mono_runtime_invoke_checked(). If an exception is thrown, you
2981 * can't use the MonoObject* result from the function.
2983 * If this method cannot be invoked, @error will be set and @exc and
2984 * the return value must not be used.
2986 * If the method returns a value type, it is boxed in an object
2990 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2992 MONO_REQ_GC_UNSAFE_MODE;
2994 g_assert (exc != NULL);
2996 if (mono_runtime_get_no_exec ())
2997 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2999 return do_runtime_invoke (method, obj, params, exc, error);
3003 * mono_runtime_invoke_checked:
3004 * @method: method to invoke
3005 * @obJ: object instance
3006 * @params: arguments to the method
3007 * @error: set on error
3009 * Invokes the method represented by @method on the object @obj.
3011 * obj is the 'this' pointer, it should be NULL for static
3012 * methods, a MonoObject* for object instances and a pointer to
3013 * the value type for value types.
3015 * The params array contains the arguments to the method with the
3016 * same convention: MonoObject* pointers for object instances and
3017 * pointers to the value type otherwise.
3019 * From unmanaged code you'll usually use the
3020 * mono_runtime_invoke() variant.
3022 * Note that this function doesn't handle virtual methods for
3023 * you, it will exec the exact method you pass: we still need to
3024 * expose a function to lookup the derived class implementation
3025 * of a virtual method (there are examples of this in the code,
3028 * If an exception is thrown, you can't use the MonoObject* result
3029 * from the function.
3031 * If this method cannot be invoked, @error will be set. If the
3032 * method throws an exception (and we're in coop mode) the exception
3033 * will be set in @error.
3035 * If the method returns a value type, it is boxed in an object
3039 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3041 MONO_REQ_GC_UNSAFE_MODE;
3043 if (mono_runtime_get_no_exec ())
3044 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3046 return do_runtime_invoke (method, obj, params, NULL, error);
3050 * mono_method_get_unmanaged_thunk:
3051 * @method: method to generate a thunk for.
3053 * Returns an unmanaged->managed thunk that can be used to call
3054 * a managed method directly from C.
3056 * The thunk's C signature closely matches the managed signature:
3058 * C#: public bool Equals (object obj);
3059 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3060 * MonoObject*, MonoException**);
3062 * The 1st ("this") parameter must not be used with static methods:
3064 * C#: public static bool ReferenceEquals (object a, object b);
3065 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3068 * The last argument must be a non-null pointer of a MonoException* pointer.
3069 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3070 * exception has been thrown in managed code. Otherwise it will point
3071 * to the MonoException* caught by the thunk. In this case, the result of
3072 * the thunk is undefined:
3074 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3075 * MonoException *ex = NULL;
3076 * Equals func = mono_method_get_unmanaged_thunk (method);
3077 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3079 * // handle exception
3082 * The calling convention of the thunk matches the platform's default
3083 * convention. This means that under Windows, C declarations must
3084 * contain the __stdcall attribute:
3086 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3087 * MonoObject*, MonoException**);
3091 * Value type arguments and return values are treated as they were objects:
3093 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3094 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3096 * Arguments must be properly boxed upon trunk's invocation, while return
3097 * values must be unboxed.
3100 mono_method_get_unmanaged_thunk (MonoMethod *method)
3102 MONO_REQ_GC_NEUTRAL_MODE;
3103 MONO_REQ_API_ENTRYPOINT;
3107 MONO_PREPARE_RESET_BLOCKING;
3108 method = mono_marshal_get_thunk_invoke_wrapper (method);
3109 res = mono_compile_method (method);
3110 MONO_FINISH_RESET_BLOCKING;
3116 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3118 MONO_REQ_GC_UNSAFE_MODE;
3122 /* object fields cannot be byref, so we don't need a
3124 gpointer *p = (gpointer*)dest;
3131 case MONO_TYPE_BOOLEAN:
3133 case MONO_TYPE_U1: {
3134 guint8 *p = (guint8*)dest;
3135 *p = value ? *(guint8*)value : 0;
3140 case MONO_TYPE_CHAR: {
3141 guint16 *p = (guint16*)dest;
3142 *p = value ? *(guint16*)value : 0;
3145 #if SIZEOF_VOID_P == 4
3150 case MONO_TYPE_U4: {
3151 gint32 *p = (gint32*)dest;
3152 *p = value ? *(gint32*)value : 0;
3155 #if SIZEOF_VOID_P == 8
3160 case MONO_TYPE_U8: {
3161 gint64 *p = (gint64*)dest;
3162 *p = value ? *(gint64*)value : 0;
3165 case MONO_TYPE_R4: {
3166 float *p = (float*)dest;
3167 *p = value ? *(float*)value : 0;
3170 case MONO_TYPE_R8: {
3171 double *p = (double*)dest;
3172 *p = value ? *(double*)value : 0;
3175 case MONO_TYPE_STRING:
3176 case MONO_TYPE_SZARRAY:
3177 case MONO_TYPE_CLASS:
3178 case MONO_TYPE_OBJECT:
3179 case MONO_TYPE_ARRAY:
3180 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3182 case MONO_TYPE_FNPTR:
3183 case MONO_TYPE_PTR: {
3184 gpointer *p = (gpointer*)dest;
3185 *p = deref_pointer? *(gpointer*)value: value;
3188 case MONO_TYPE_VALUETYPE:
3189 /* note that 't' and 'type->type' can be different */
3190 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3191 t = mono_class_enum_basetype (type->data.klass)->type;
3194 MonoClass *klass = mono_class_from_mono_type (type);
3195 int size = mono_class_value_size (klass, NULL);
3197 mono_gc_bzero_atomic (dest, size);
3199 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3202 case MONO_TYPE_GENERICINST:
3203 t = type->data.generic_class->container_class->byval_arg.type;
3206 g_error ("got type %x", type->type);
3211 * mono_field_set_value:
3212 * @obj: Instance object
3213 * @field: MonoClassField describing the field to set
3214 * @value: The value to be set
3216 * Sets the value of the field described by @field in the object instance @obj
3217 * to the value passed in @value. This method should only be used for instance
3218 * fields. For static fields, use mono_field_static_set_value.
3220 * The value must be on the native format of the field type.
3223 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3225 MONO_REQ_GC_UNSAFE_MODE;
3229 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3231 dest = (char*)obj + field->offset;
3232 mono_copy_value (field->type, dest, value, FALSE);
3236 * mono_field_static_set_value:
3237 * @field: MonoClassField describing the field to set
3238 * @value: The value to be set
3240 * Sets the value of the static field described by @field
3241 * to the value passed in @value.
3243 * The value must be on the native format of the field type.
3246 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3248 MONO_REQ_GC_UNSAFE_MODE;
3252 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3253 /* you cant set a constant! */
3254 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3256 if (field->offset == -1) {
3257 /* Special static */
3260 mono_domain_lock (vt->domain);
3261 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3262 mono_domain_unlock (vt->domain);
3263 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3265 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3267 mono_copy_value (field->type, dest, value, FALSE);
3271 * mono_vtable_get_static_field_data:
3273 * Internal use function: return a pointer to the memory holding the static fields
3274 * for a class or NULL if there are no static fields.
3275 * This is exported only for use by the debugger.
3278 mono_vtable_get_static_field_data (MonoVTable *vt)
3280 MONO_REQ_GC_NEUTRAL_MODE
3282 if (!vt->has_static_fields)
3284 return vt->vtable [vt->klass->vtable_size];
3288 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3290 MONO_REQ_GC_UNSAFE_MODE;
3294 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3295 if (field->offset == -1) {
3296 /* Special static */
3299 mono_domain_lock (vt->domain);
3300 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3301 mono_domain_unlock (vt->domain);
3302 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3304 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3307 src = (guint8*)obj + field->offset;
3314 * mono_field_get_value:
3315 * @obj: Object instance
3316 * @field: MonoClassField describing the field to fetch information from
3317 * @value: pointer to the location where the value will be stored
3319 * Use this routine to get the value of the field @field in the object
3322 * The pointer provided by value must be of the field type, for reference
3323 * types this is a MonoObject*, for value types its the actual pointer to
3328 * mono_field_get_value (obj, int_field, &i);
3331 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3333 MONO_REQ_GC_UNSAFE_MODE;
3339 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3341 src = (char*)obj + field->offset;
3342 mono_copy_value (field->type, value, src, TRUE);
3346 * mono_field_get_value_object:
3347 * @domain: domain where the object will be created (if boxing)
3348 * @field: MonoClassField describing the field to fetch information from
3349 * @obj: The object instance for the field.
3351 * Returns: a new MonoObject with the value from the given field. If the
3352 * field represents a value type, the value is boxed.
3356 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3358 MONO_REQ_GC_UNSAFE_MODE;
3363 MonoVTable *vtable = NULL;
3365 gboolean is_static = FALSE;
3366 gboolean is_ref = FALSE;
3367 gboolean is_literal = FALSE;
3368 gboolean is_ptr = FALSE;
3369 MonoType *type = mono_field_get_type_checked (field, &error);
3371 if (!mono_error_ok (&error))
3372 mono_error_raise_exception (&error); /* FIXME don't raise here */
3374 switch (type->type) {
3375 case MONO_TYPE_STRING:
3376 case MONO_TYPE_OBJECT:
3377 case MONO_TYPE_CLASS:
3378 case MONO_TYPE_ARRAY:
3379 case MONO_TYPE_SZARRAY:
3384 case MONO_TYPE_BOOLEAN:
3387 case MONO_TYPE_CHAR:
3396 case MONO_TYPE_VALUETYPE:
3397 is_ref = type->byref;
3399 case MONO_TYPE_GENERICINST:
3400 is_ref = !mono_type_generic_inst_is_valuetype (type);
3406 g_error ("type 0x%x not handled in "
3407 "mono_field_get_value_object", type->type);
3411 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3414 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3418 vtable = mono_class_vtable_full (domain, field->parent, &error);
3419 mono_error_raise_exception (&error); /* FIXME don't raise here */
3421 if (!vtable->initialized) {
3422 mono_runtime_class_init_full (vtable, &error);
3423 mono_error_raise_exception (&error); /* FIXME don't raise here */
3432 get_default_field_value (domain, field, &o);
3433 } else if (is_static) {
3434 mono_field_static_get_value (vtable, field, &o);
3436 mono_field_get_value (obj, field, &o);
3442 static MonoMethod *m;
3448 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3449 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3455 get_default_field_value (domain, field, v);
3456 } else if (is_static) {
3457 mono_field_static_get_value (vtable, field, v);
3459 mono_field_get_value (obj, field, v);
3462 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3463 args [0] = ptr ? *ptr : NULL;
3464 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3465 mono_error_raise_exception (&error); /* FIXME don't raise here */
3467 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3468 mono_error_raise_exception (&error); /* FIXME don't raise here */
3473 /* boxed value type */
3474 klass = mono_class_from_mono_type (type);
3476 if (mono_class_is_nullable (klass))
3477 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3479 o = mono_object_new_checked (domain, klass, &error);
3480 mono_error_raise_exception (&error); /* FIXME don't raise here */
3481 v = ((gchar *) o) + sizeof (MonoObject);
3484 get_default_field_value (domain, field, v);
3485 } else if (is_static) {
3486 mono_field_static_get_value (vtable, field, v);
3488 mono_field_get_value (obj, field, v);
3495 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3497 MONO_REQ_GC_UNSAFE_MODE;
3500 const char *p = blob;
3501 mono_metadata_decode_blob_size (p, &p);
3504 case MONO_TYPE_BOOLEAN:
3507 *(guint8 *) value = *p;
3509 case MONO_TYPE_CHAR:
3512 *(guint16*) value = read16 (p);
3516 *(guint32*) value = read32 (p);
3520 *(guint64*) value = read64 (p);
3523 readr4 (p, (float*) value);
3526 readr8 (p, (double*) value);
3528 case MONO_TYPE_STRING:
3529 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3531 case MONO_TYPE_CLASS:
3532 *(gpointer*) value = NULL;
3536 g_warning ("type 0x%02x should not be in constant table", type);
3542 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3544 MONO_REQ_GC_NEUTRAL_MODE;
3546 MonoTypeEnum def_type;
3549 data = mono_class_get_field_default_value (field, &def_type);
3550 mono_get_constant_value_from_blob (domain, def_type, data, value);
3554 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3556 MONO_REQ_GC_UNSAFE_MODE;
3560 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3562 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3563 get_default_field_value (vt->domain, field, value);
3567 if (field->offset == -1) {
3568 /* Special static */
3569 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3570 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3572 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3574 mono_copy_value (field->type, value, src, TRUE);
3578 * mono_field_static_get_value:
3579 * @vt: vtable to the object
3580 * @field: MonoClassField describing the field to fetch information from
3581 * @value: where the value is returned
3583 * Use this routine to get the value of the static field @field value.
3585 * The pointer provided by value must be of the field type, for reference
3586 * types this is a MonoObject*, for value types its the actual pointer to
3591 * mono_field_static_get_value (vt, int_field, &i);
3594 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3596 MONO_REQ_GC_NEUTRAL_MODE;
3598 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3602 * mono_property_set_value:
3603 * @prop: MonoProperty to set
3604 * @obj: instance object on which to act
3605 * @params: parameters to pass to the propery
3606 * @exc: optional exception
3608 * Invokes the property's set method with the given arguments on the
3609 * object instance obj (or NULL for static properties).
3611 * You can pass NULL as the exc argument if you don't want to
3612 * catch exceptions, otherwise, *exc will be set to the exception
3613 * thrown, if any. if an exception is thrown, you can't use the
3614 * MonoObject* result from the function.
3617 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3619 MONO_REQ_GC_UNSAFE_MODE;
3622 do_runtime_invoke (prop->set, obj, params, exc, &error);
3623 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3624 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3626 mono_error_raise_exception (&error); /* FIXME don't raise here */
3631 * mono_property_get_value:
3632 * @prop: MonoProperty to fetch
3633 * @obj: instance object on which to act
3634 * @params: parameters to pass to the propery
3635 * @exc: optional exception
3637 * Invokes the property's get method with the given arguments on the
3638 * object instance obj (or NULL for static properties).
3640 * You can pass NULL as the exc argument if you don't want to
3641 * catch exceptions, otherwise, *exc will be set to the exception
3642 * thrown, if any. if an exception is thrown, you can't use the
3643 * MonoObject* result from the function.
3645 * Returns: the value from invoking the get method on the property.
3648 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3650 MONO_REQ_GC_UNSAFE_MODE;
3653 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3654 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3655 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3657 mono_error_raise_exception (&error); /* FIXME don't raise here */
3664 * mono_nullable_init:
3665 * @buf: The nullable structure to initialize.
3666 * @value: the value to initialize from
3667 * @klass: the type for the object
3669 * Initialize the nullable structure pointed to by @buf from @value which
3670 * should be a boxed value type. The size of @buf should be able to hold
3671 * as much data as the @klass->instance_size (which is the number of bytes
3672 * that will be copies).
3674 * Since Nullables have variable structure, we can not define a C
3675 * structure for them.
3678 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3680 MONO_REQ_GC_UNSAFE_MODE;
3682 MonoClass *param_class = klass->cast_class;
3684 mono_class_setup_fields_locking (klass);
3685 g_assert (klass->fields_inited);
3687 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3688 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3690 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3692 if (param_class->has_references)
3693 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3695 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3697 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3702 * mono_nullable_box:
3703 * @buf: The buffer representing the data to be boxed
3704 * @klass: the type to box it as.
3706 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3710 mono_nullable_box (guint8 *buf, MonoClass *klass)
3712 MONO_REQ_GC_UNSAFE_MODE;
3716 MonoClass *param_class = klass->cast_class;
3718 mono_class_setup_fields_locking (klass);
3719 g_assert (klass->fields_inited);
3721 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3722 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3724 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3725 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3726 mono_error_raise_exception (&error); /* FIXME don't raise here */
3727 if (param_class->has_references)
3728 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3730 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3738 * mono_get_delegate_invoke:
3739 * @klass: The delegate class
3741 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3744 mono_get_delegate_invoke (MonoClass *klass)
3746 MONO_REQ_GC_NEUTRAL_MODE;
3750 /* This is called at runtime, so avoid the slower search in metadata */
3751 mono_class_setup_methods (klass);
3752 if (mono_class_has_failure (klass))
3754 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3759 * mono_get_delegate_begin_invoke:
3760 * @klass: The delegate class
3762 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3765 mono_get_delegate_begin_invoke (MonoClass *klass)
3767 MONO_REQ_GC_NEUTRAL_MODE;
3771 /* This is called at runtime, so avoid the slower search in metadata */
3772 mono_class_setup_methods (klass);
3773 if (mono_class_has_failure (klass))
3775 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3780 * mono_get_delegate_end_invoke:
3781 * @klass: The delegate class
3783 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3786 mono_get_delegate_end_invoke (MonoClass *klass)
3788 MONO_REQ_GC_NEUTRAL_MODE;
3792 /* This is called at runtime, so avoid the slower search in metadata */
3793 mono_class_setup_methods (klass);
3794 if (mono_class_has_failure (klass))
3796 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3801 * mono_runtime_delegate_invoke:
3802 * @delegate: pointer to a delegate object.
3803 * @params: parameters for the delegate.
3804 * @exc: Pointer to the exception result.
3806 * Invokes the delegate method @delegate with the parameters provided.
3808 * You can pass NULL as the exc argument if you don't want to
3809 * catch exceptions, otherwise, *exc will be set to the exception
3810 * thrown, if any. if an exception is thrown, you can't use the
3811 * MonoObject* result from the function.
3814 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3816 MONO_REQ_GC_UNSAFE_MODE;
3820 MonoClass *klass = delegate->vtable->klass;
3823 im = mono_get_delegate_invoke (klass);
3825 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3828 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3829 if (*exc == NULL && !mono_error_ok (&error))
3830 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3832 mono_error_cleanup (&error);
3834 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3835 mono_error_raise_exception (&error); /* FIXME don't raise here */
3841 static char **main_args = NULL;
3842 static int num_main_args = 0;
3845 * mono_runtime_get_main_args:
3847 * Returns: a MonoArray with the arguments passed to the main program
3850 mono_runtime_get_main_args (void)
3852 MONO_REQ_GC_UNSAFE_MODE;
3856 MonoDomain *domain = mono_domain_get ();
3858 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3860 for (i = 0; i < num_main_args; ++i)
3861 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3867 free_main_args (void)
3869 MONO_REQ_GC_NEUTRAL_MODE;
3873 for (i = 0; i < num_main_args; ++i)
3874 g_free (main_args [i]);
3881 * mono_runtime_set_main_args:
3882 * @argc: number of arguments from the command line
3883 * @argv: array of strings from the command line
3885 * Set the command line arguments from an embedding application that doesn't otherwise call
3886 * mono_runtime_run_main ().
3889 mono_runtime_set_main_args (int argc, char* argv[])
3891 MONO_REQ_GC_NEUTRAL_MODE;
3896 main_args = g_new0 (char*, argc);
3897 num_main_args = argc;
3899 for (i = 0; i < argc; ++i) {
3902 utf8_arg = mono_utf8_from_external (argv[i]);
3903 if (utf8_arg == NULL) {
3904 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3905 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3909 main_args [i] = utf8_arg;
3916 * mono_runtime_run_main:
3917 * @method: the method to start the application with (usually Main)
3918 * @argc: number of arguments from the command line
3919 * @argv: array of strings from the command line
3920 * @exc: excetption results
3922 * Execute a standard Main() method (argc/argv contains the
3923 * executable name). This method also sets the command line argument value
3924 * needed by System.Environment.
3929 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3932 MONO_REQ_GC_UNSAFE_MODE;
3935 MonoArray *args = NULL;
3936 MonoDomain *domain = mono_domain_get ();
3937 gchar *utf8_fullpath;
3938 MonoMethodSignature *sig;
3940 g_assert (method != NULL);
3942 mono_thread_set_main (mono_thread_current ());
3944 main_args = g_new0 (char*, argc);
3945 num_main_args = argc;
3947 if (!g_path_is_absolute (argv [0])) {
3948 gchar *basename = g_path_get_basename (argv [0]);
3949 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3953 utf8_fullpath = mono_utf8_from_external (fullpath);
3954 if(utf8_fullpath == NULL) {
3955 /* Printing the arg text will cause glib to
3956 * whinge about "Invalid UTF-8", but at least
3957 * its relevant, and shows the problem text
3960 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3961 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3968 utf8_fullpath = mono_utf8_from_external (argv[0]);
3969 if(utf8_fullpath == NULL) {
3970 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3971 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3976 main_args [0] = utf8_fullpath;
3978 for (i = 1; i < argc; ++i) {
3981 utf8_arg=mono_utf8_from_external (argv[i]);
3982 if(utf8_arg==NULL) {
3983 /* Ditto the comment about Invalid UTF-8 here */
3984 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3985 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3989 main_args [i] = utf8_arg;
3994 sig = mono_method_signature (method);
3996 g_print ("Unable to load Main method.\n");
4000 if (sig->param_count) {
4001 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
4002 for (i = 0; i < argc; ++i) {
4003 /* The encodings should all work, given that
4004 * we've checked all these args for the
4007 gchar *str = mono_utf8_from_external (argv [i]);
4008 MonoString *arg = mono_string_new (domain, str);
4009 mono_array_setref (args, i, arg);
4013 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4016 mono_assembly_set_main (method->klass->image->assembly);
4018 return mono_runtime_exec_main (method, args, exc);
4022 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4024 static MonoMethod *serialize_method;
4030 if (!serialize_method) {
4031 MonoClass *klass = mono_class_get_remoting_services_class ();
4032 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4035 if (!serialize_method) {
4040 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4045 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4046 if (*exc == NULL && !mono_error_ok (&error))
4047 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4049 mono_error_cleanup (&error);
4058 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4060 MONO_REQ_GC_UNSAFE_MODE;
4062 static MonoMethod *deserialize_method;
4068 if (!deserialize_method) {
4069 MonoClass *klass = mono_class_get_remoting_services_class ();
4070 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4072 if (!deserialize_method) {
4080 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4081 if (*exc == NULL && !mono_error_ok (&error))
4082 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4084 mono_error_cleanup (&error);
4092 #ifndef DISABLE_REMOTING
4094 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4096 MONO_REQ_GC_UNSAFE_MODE;
4098 static MonoMethod *get_proxy_method;
4101 MonoDomain *domain = mono_domain_get ();
4102 MonoRealProxy *real_proxy;
4103 MonoReflectionType *reflection_type;
4104 MonoTransparentProxy *transparent_proxy;
4106 if (!get_proxy_method)
4107 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4109 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4111 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4112 mono_error_raise_exception (&error); /* FIXME don't raise here */
4113 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4114 mono_error_raise_exception (&error); /* FIXME don't raise here */
4116 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4117 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4121 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4122 if (*exc == NULL && !mono_error_ok (&error))
4123 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4125 mono_error_cleanup (&error);
4129 return (MonoObject*) transparent_proxy;
4131 #endif /* DISABLE_REMOTING */
4134 * mono_object_xdomain_representation
4136 * @target_domain: a domain
4137 * @exc: pointer to a MonoObject*
4139 * Creates a representation of obj in the domain target_domain. This
4140 * is either a copy of obj arrived through via serialization and
4141 * deserialization or a proxy, depending on whether the object is
4142 * serializable or marshal by ref. obj must not be in target_domain.
4144 * If the object cannot be represented in target_domain, NULL is
4145 * returned and *exc is set to an appropriate exception.
4148 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4150 MONO_REQ_GC_UNSAFE_MODE;
4152 MonoObject *deserialized = NULL;
4153 gboolean failure = FALSE;
4155 g_assert (exc != NULL);
4158 #ifndef DISABLE_REMOTING
4159 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4160 deserialized = make_transparent_proxy (obj, &failure, exc);
4165 MonoDomain *domain = mono_domain_get ();
4166 MonoObject *serialized;
4168 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4169 serialized = serialize_object (obj, &failure, exc);
4170 mono_domain_set_internal_with_options (target_domain, FALSE);
4172 deserialized = deserialize_object (serialized, &failure, exc);
4173 if (domain != target_domain)
4174 mono_domain_set_internal_with_options (domain, FALSE);
4177 return deserialized;
4180 /* Used in call_unhandled_exception_delegate */
4182 create_unhandled_exception_eventargs (MonoObject *exc)
4184 MONO_REQ_GC_UNSAFE_MODE;
4189 MonoMethod *method = NULL;
4190 MonoBoolean is_terminating = TRUE;
4193 klass = mono_class_get_unhandled_exception_event_args_class ();
4194 mono_class_init (klass);
4196 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4197 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4201 args [1] = &is_terminating;
4203 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4204 mono_error_raise_exception (&error); /* FIXME don't raise here */
4206 mono_runtime_invoke_checked (method, obj, args, &error);
4207 mono_error_raise_exception (&error); /* FIXME don't raise here */
4212 /* Used in mono_unhandled_exception */
4214 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4215 MONO_REQ_GC_UNSAFE_MODE;
4217 MonoObject *e = NULL;
4219 MonoDomain *current_domain = mono_domain_get ();
4221 if (domain != current_domain)
4222 mono_domain_set_internal_with_options (domain, FALSE);
4224 g_assert (domain == mono_object_domain (domain->domain));
4226 if (mono_object_domain (exc) != domain) {
4227 MonoObject *serialization_exc;
4229 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4231 if (serialization_exc) {
4233 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4236 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4237 "System.Runtime.Serialization", "SerializationException",
4238 "Could not serialize unhandled exception.");
4242 g_assert (mono_object_domain (exc) == domain);
4244 pa [0] = domain->domain;
4245 pa [1] = create_unhandled_exception_eventargs (exc);
4246 mono_runtime_delegate_invoke (delegate, pa, &e);
4248 if (domain != current_domain)
4249 mono_domain_set_internal_with_options (current_domain, FALSE);
4253 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4254 if (!mono_error_ok (&error)) {
4255 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4256 mono_error_cleanup (&error);
4258 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4264 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4267 * mono_runtime_unhandled_exception_policy_set:
4268 * @policy: the new policy
4270 * This is a VM internal routine.
4272 * Sets the runtime policy for handling unhandled exceptions.
4275 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4276 runtime_unhandled_exception_policy = policy;
4280 * mono_runtime_unhandled_exception_policy_get:
4282 * This is a VM internal routine.
4284 * Gets the runtime policy for handling unhandled exceptions.
4286 MonoRuntimeUnhandledExceptionPolicy
4287 mono_runtime_unhandled_exception_policy_get (void) {
4288 return runtime_unhandled_exception_policy;
4292 * mono_unhandled_exception:
4293 * @exc: exception thrown
4295 * This is a VM internal routine.
4297 * We call this function when we detect an unhandled exception
4298 * in the default domain.
4300 * It invokes the * UnhandledException event in AppDomain or prints
4301 * a warning to the console
4304 mono_unhandled_exception (MonoObject *exc)
4306 MONO_REQ_GC_UNSAFE_MODE;
4308 MonoClassField *field;
4309 MonoDomain *current_domain, *root_domain;
4310 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4312 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4315 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4318 current_domain = mono_domain_get ();
4319 root_domain = mono_get_root_domain ();
4321 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4322 if (current_domain != root_domain)
4323 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4325 /* set exitcode only if we will abort the process */
4326 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4327 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4328 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4330 mono_environment_exitcode_set (1);
4333 mono_print_unhandled_exception (exc);
4335 if (root_appdomain_delegate)
4336 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4337 if (current_appdomain_delegate)
4338 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4343 * mono_runtime_exec_managed_code:
4344 * @domain: Application domain
4345 * @main_func: function to invoke from the execution thread
4346 * @main_args: parameter to the main_func
4348 * Launch a new thread to execute a function
4350 * main_func is called back from the thread with main_args as the
4351 * parameter. The callback function is expected to start Main()
4352 * eventually. This function then waits for all managed threads to
4354 * It is not necesseray anymore to execute managed code in a subthread,
4355 * so this function should not be used anymore by default: just
4356 * execute the code and then call mono_thread_manage ().
4359 mono_runtime_exec_managed_code (MonoDomain *domain,
4360 MonoMainThreadFunc main_func,
4363 mono_thread_create (domain, main_func, main_args);
4365 mono_thread_manage ();
4369 * Execute a standard Main() method (args doesn't contain the
4373 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4375 MONO_REQ_GC_UNSAFE_MODE;
4381 MonoCustomAttrInfo* cinfo;
4382 gboolean has_stathread_attribute;
4383 MonoInternalThread* thread = mono_thread_internal_current ();
4389 domain = mono_object_domain (args);
4390 if (!domain->entry_assembly) {
4392 MonoAssembly *assembly;
4394 assembly = method->klass->image->assembly;
4395 domain->entry_assembly = assembly;
4396 /* Domains created from another domain already have application_base and configuration_file set */
4397 if (domain->setup->application_base == NULL) {
4398 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4401 if (domain->setup->configuration_file == NULL) {
4402 str = g_strconcat (assembly->image->name, ".config", NULL);
4403 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4405 mono_domain_set_options_from_config (domain);
4409 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4410 mono_error_cleanup (&error); /* FIXME warn here? */
4412 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4414 mono_custom_attrs_free (cinfo);
4416 has_stathread_attribute = FALSE;
4418 if (has_stathread_attribute) {
4419 thread->apartment_state = ThreadApartmentState_STA;
4421 thread->apartment_state = ThreadApartmentState_MTA;
4423 mono_thread_init_apartment_state ();
4425 /* FIXME: check signature of method */
4426 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4429 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4430 if (*exc == NULL && !mono_error_ok (&error))
4431 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4433 mono_error_cleanup (&error);
4435 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4436 mono_error_raise_exception (&error); /* FIXME don't raise here */
4440 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4444 mono_environment_exitcode_set (rval);
4447 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4448 if (*exc == NULL && !mono_error_ok (&error))
4449 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4451 mono_error_cleanup (&error);
4453 mono_runtime_invoke_checked (method, NULL, pa, &error);
4454 mono_error_raise_exception (&error); /* FIXME don't raise here */
4460 /* If the return type of Main is void, only
4461 * set the exitcode if an exception was thrown
4462 * (we don't want to blow away an
4463 * explicitly-set exit code)
4466 mono_environment_exitcode_set (rval);
4474 * mono_runtime_invoke_array:
4475 * @method: method to invoke
4476 * @obJ: object instance
4477 * @params: arguments to the method
4478 * @exc: exception information.
4480 * Invokes the method represented by @method on the object @obj.
4482 * obj is the 'this' pointer, it should be NULL for static
4483 * methods, a MonoObject* for object instances and a pointer to
4484 * the value type for value types.
4486 * The params array contains the arguments to the method with the
4487 * same convention: MonoObject* pointers for object instances and
4488 * pointers to the value type otherwise. The _invoke_array
4489 * variant takes a C# object[] as the params argument (MonoArray
4490 * *params): in this case the value types are boxed inside the
4491 * respective reference representation.
4493 * From unmanaged code you'll usually use the
4494 * mono_runtime_invoke_checked() variant.
4496 * Note that this function doesn't handle virtual methods for
4497 * you, it will exec the exact method you pass: we still need to
4498 * expose a function to lookup the derived class implementation
4499 * of a virtual method (there are examples of this in the code,
4502 * You can pass NULL as the exc argument if you don't want to
4503 * catch exceptions, otherwise, *exc will be set to the exception
4504 * thrown, if any. if an exception is thrown, you can't use the
4505 * MonoObject* result from the function.
4507 * If the method returns a value type, it is boxed in an object
4511 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4514 MONO_REQ_GC_UNSAFE_MODE;
4517 MonoMethodSignature *sig = mono_method_signature (method);
4518 gpointer *pa = NULL;
4521 gboolean has_byref_nullables = FALSE;
4523 if (NULL != params) {
4524 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4525 for (i = 0; i < mono_array_length (params); i++) {
4526 MonoType *t = sig->params [i];
4532 case MONO_TYPE_BOOLEAN:
4535 case MONO_TYPE_CHAR:
4544 case MONO_TYPE_VALUETYPE:
4545 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4546 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4547 pa [i] = mono_array_get (params, MonoObject*, i);
4549 has_byref_nullables = TRUE;
4551 /* MS seems to create the objects if a null is passed in */
4552 if (!mono_array_get (params, MonoObject*, i)) {
4553 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4554 mono_error_raise_exception (&error); /* FIXME don't raise here */
4555 mono_array_setref (params, i, o);
4560 * We can't pass the unboxed vtype byref to the callee, since
4561 * that would mean the callee would be able to modify boxed
4562 * primitive types. So we (and MS) make a copy of the boxed
4563 * object, pass that to the callee, and replace the original
4564 * boxed object in the arg array with the copy.
4566 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4567 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4568 mono_array_setref (params, i, copy);
4571 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4574 case MONO_TYPE_STRING:
4575 case MONO_TYPE_OBJECT:
4576 case MONO_TYPE_CLASS:
4577 case MONO_TYPE_ARRAY:
4578 case MONO_TYPE_SZARRAY:
4580 pa [i] = mono_array_addr (params, MonoObject*, i);
4581 // FIXME: I need to check this code path
4583 pa [i] = mono_array_get (params, MonoObject*, i);
4585 case MONO_TYPE_GENERICINST:
4587 t = &t->data.generic_class->container_class->this_arg;
4589 t = &t->data.generic_class->container_class->byval_arg;
4591 case MONO_TYPE_PTR: {
4594 /* The argument should be an IntPtr */
4595 arg = mono_array_get (params, MonoObject*, i);
4599 g_assert (arg->vtable->klass == mono_defaults.int_class);
4600 pa [i] = ((MonoIntPtr*)arg)->m_value;
4605 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4610 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4613 if (mono_class_is_nullable (method->klass)) {
4614 /* Need to create a boxed vtype instead */
4620 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4624 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4625 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4626 #ifndef DISABLE_REMOTING
4627 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4628 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4631 if (method->klass->valuetype)
4632 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4635 } else if (method->klass->valuetype) {
4636 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4640 mono_runtime_try_invoke (method, o, pa, exc, &error);
4641 if (*exc == NULL && !mono_error_ok (&error))
4642 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4644 mono_error_cleanup (&error);
4646 mono_runtime_invoke_checked (method, o, pa, &error);
4647 mono_error_raise_exception (&error); /* FIXME don't raise here */
4650 return (MonoObject *)obj;
4652 if (mono_class_is_nullable (method->klass)) {
4653 MonoObject *nullable;
4655 /* Convert the unboxed vtype into a Nullable structure */
4656 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4657 mono_error_raise_exception (&error); /* FIXME don't raise here */
4659 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4660 obj = mono_object_unbox (nullable);
4663 /* obj must be already unboxed if needed */
4665 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4666 if (*exc == NULL && !mono_error_ok (&error))
4667 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4669 mono_error_cleanup (&error);
4671 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4672 mono_error_raise_exception (&error); /* FIXME don't raise here */
4675 if (sig->ret->type == MONO_TYPE_PTR) {
4676 MonoClass *pointer_class;
4677 static MonoMethod *box_method;
4679 MonoObject *box_exc;
4682 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4683 * convert it to a Pointer object.
4685 pointer_class = mono_class_get_pointer_class ();
4687 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4689 g_assert (res->vtable->klass == mono_defaults.int_class);
4690 box_args [0] = ((MonoIntPtr*)res)->m_value;
4691 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4692 mono_error_raise_exception (&error); /* FIXME don't raise here */
4694 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4695 g_assert (box_exc == NULL);
4696 mono_error_assert_ok (&error);
4699 if (has_byref_nullables) {
4701 * The runtime invoke wrapper already converted byref nullables back,
4702 * and stored them in pa, we just need to copy them back to the
4705 for (i = 0; i < mono_array_length (params); i++) {
4706 MonoType *t = sig->params [i];
4708 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4709 mono_array_setref (params, i, pa [i]);
4719 * @klass: the class of the object that we want to create
4721 * Returns: a newly created object whose definition is
4722 * looked up using @klass. This will not invoke any constructors,
4723 * so the consumer of this routine has to invoke any constructors on
4724 * its own to initialize the object.
4726 * It returns NULL on failure.
4729 mono_object_new (MonoDomain *domain, MonoClass *klass)
4731 MONO_REQ_GC_UNSAFE_MODE;
4735 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4737 mono_error_raise_exception (&error);
4742 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4744 MONO_REQ_GC_UNSAFE_MODE;
4748 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4750 mono_error_raise_exception (&error);
4755 * mono_object_new_checked:
4756 * @klass: the class of the object that we want to create
4757 * @error: set on error
4759 * Returns: a newly created object whose definition is
4760 * looked up using @klass. This will not invoke any constructors,
4761 * so the consumer of this routine has to invoke any constructors on
4762 * its own to initialize the object.
4764 * It returns NULL on failure and sets @error.
4767 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4769 MONO_REQ_GC_UNSAFE_MODE;
4773 vtable = mono_class_vtable (domain, klass);
4774 g_assert (vtable); /* FIXME don't swallow the error */
4776 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4781 * mono_object_new_pinned:
4783 * Same as mono_object_new, but the returned object will be pinned.
4784 * For SGEN, these objects will only be freed at appdomain unload.
4787 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4789 MONO_REQ_GC_UNSAFE_MODE;
4793 mono_error_init (error);
4795 vtable = mono_class_vtable (domain, klass);
4796 g_assert (vtable); /* FIXME don't swallow the error */
4798 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4800 if (G_UNLIKELY (!o))
4801 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4802 else if (G_UNLIKELY (vtable->klass->has_finalize))
4803 mono_object_register_finalizer (o, error);
4809 * mono_object_new_specific:
4810 * @vtable: the vtable of the object that we want to create
4812 * Returns: A newly created object with class and domain specified
4816 mono_object_new_specific (MonoVTable *vtable)
4819 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4820 mono_error_raise_exception (&error);
4826 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4828 MONO_REQ_GC_UNSAFE_MODE;
4832 mono_error_init (error);
4834 /* check for is_com_object for COM Interop */
4835 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4838 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4841 MonoClass *klass = mono_class_get_activation_services_class ();
4844 mono_class_init (klass);
4846 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4848 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4851 vtable->domain->create_proxy_for_type_method = im;
4854 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4855 if (!mono_error_ok (error))
4858 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4859 if (!mono_error_ok (error))
4866 return mono_object_new_alloc_specific_checked (vtable, error);
4870 ves_icall_object_new_specific (MonoVTable *vtable)
4873 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4874 mono_error_raise_exception (&error);
4880 * mono_object_new_alloc_specific:
4881 * @vtable: virtual table for the object.
4883 * This function allocates a new `MonoObject` with the type derived
4884 * from the @vtable information. If the class of this object has a
4885 * finalizer, then the object will be tracked for finalization.
4887 * This method might raise an exception on errors. Use the
4888 * `mono_object_new_fast_checked` method if you want to manually raise
4891 * Returns: the allocated object.
4894 mono_object_new_alloc_specific (MonoVTable *vtable)
4897 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4898 mono_error_raise_exception (&error);
4904 * mono_object_new_alloc_specific_checked:
4905 * @vtable: virtual table for the object.
4906 * @error: holds the error return value.
4908 * This function allocates a new `MonoObject` with the type derived
4909 * from the @vtable information. If the class of this object has a
4910 * finalizer, then the object will be tracked for finalization.
4912 * If there is not enough memory, the @error parameter will be set
4913 * and will contain a user-visible message with the amount of bytes
4914 * that were requested.
4916 * Returns: the allocated object, or NULL if there is not enough memory
4920 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4922 MONO_REQ_GC_UNSAFE_MODE;
4926 mono_error_init (error);
4928 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4930 if (G_UNLIKELY (!o))
4931 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4932 else if (G_UNLIKELY (vtable->klass->has_finalize))
4933 mono_object_register_finalizer (o, error);
4939 * mono_object_new_fast:
4940 * @vtable: virtual table for the object.
4942 * This function allocates a new `MonoObject` with the type derived
4943 * from the @vtable information. The returned object is not tracked
4944 * for finalization. If your object implements a finalizer, you should
4945 * use `mono_object_new_alloc_specific` instead.
4947 * This method might raise an exception on errors. Use the
4948 * `mono_object_new_fast_checked` method if you want to manually raise
4951 * Returns: the allocated object.
4954 mono_object_new_fast (MonoVTable *vtable)
4957 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4958 mono_error_raise_exception (&error);
4964 * mono_object_new_fast_checked:
4965 * @vtable: virtual table for the object.
4966 * @error: holds the error return value.
4968 * This function allocates a new `MonoObject` with the type derived
4969 * from the @vtable information. The returned object is not tracked
4970 * for finalization. If your object implements a finalizer, you should
4971 * use `mono_object_new_alloc_specific_checked` instead.
4973 * If there is not enough memory, the @error parameter will be set
4974 * and will contain a user-visible message with the amount of bytes
4975 * that were requested.
4977 * Returns: the allocated object, or NULL if there is not enough memory
4981 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4983 MONO_REQ_GC_UNSAFE_MODE;
4987 mono_error_init (error);
4989 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4991 if (G_UNLIKELY (!o))
4992 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4998 ves_icall_object_new_fast (MonoVTable *vtable)
5001 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5002 mono_error_raise_exception (&error);
5008 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5010 MONO_REQ_GC_UNSAFE_MODE;
5014 mono_error_init (error);
5016 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5018 if (G_UNLIKELY (!o))
5019 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5020 else if (G_UNLIKELY (vtable->klass->has_finalize))
5021 mono_object_register_finalizer (o, error);
5027 * mono_class_get_allocation_ftn:
5029 * @for_box: the object will be used for boxing
5030 * @pass_size_in_words:
5032 * Return the allocation function appropriate for the given class.
5036 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5038 MONO_REQ_GC_NEUTRAL_MODE;
5040 *pass_size_in_words = FALSE;
5042 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5043 return ves_icall_object_new_specific;
5045 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5047 return ves_icall_object_new_fast;
5050 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5051 * of the overhead of parameter passing.
5054 *pass_size_in_words = TRUE;
5055 #ifdef GC_REDIRECT_TO_LOCAL
5056 return GC_local_gcj_fast_malloc;
5058 return GC_gcj_fast_malloc;
5063 return ves_icall_object_new_specific;
5067 * mono_object_new_from_token:
5068 * @image: Context where the type_token is hosted
5069 * @token: a token of the type that we want to create
5071 * Returns: A newly created object whose definition is
5072 * looked up using @token in the @image image
5075 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5077 MONO_REQ_GC_UNSAFE_MODE;
5083 klass = mono_class_get_checked (image, token, &error);
5084 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5086 result = mono_object_new_checked (domain, klass, &error);
5088 mono_error_raise_exception (&error); /* FIXME don't raise here */
5095 * mono_object_clone:
5096 * @obj: the object to clone
5098 * Returns: A newly created object who is a shallow copy of @obj
5101 mono_object_clone (MonoObject *obj)
5104 MonoObject *o = mono_object_clone_checked (obj, &error);
5105 mono_error_raise_exception (&error);
5111 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5113 MONO_REQ_GC_UNSAFE_MODE;
5118 mono_error_init (error);
5120 size = obj->vtable->klass->instance_size;
5122 if (obj->vtable->klass->rank)
5123 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5125 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5127 if (G_UNLIKELY (!o)) {
5128 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5132 /* If the object doesn't contain references this will do a simple memmove. */
5133 mono_gc_wbarrier_object_copy (o, obj);
5135 if (obj->vtable->klass->has_finalize)
5136 mono_object_register_finalizer (o, error);
5141 * mono_array_full_copy:
5142 * @src: source array to copy
5143 * @dest: destination array
5145 * Copies the content of one array to another with exactly the same type and size.
5148 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5150 MONO_REQ_GC_UNSAFE_MODE;
5153 MonoClass *klass = src->obj.vtable->klass;
5155 g_assert (klass == dest->obj.vtable->klass);
5157 size = mono_array_length (src);
5158 g_assert (size == mono_array_length (dest));
5159 size *= mono_array_element_size (klass);
5161 if (klass->element_class->valuetype) {
5162 if (klass->element_class->has_references)
5163 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5165 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5167 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5170 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5175 * mono_array_clone_in_domain:
5176 * @domain: the domain in which the array will be cloned into
5177 * @array: the array to clone
5179 * This routine returns a copy of the array that is hosted on the
5180 * specified MonoDomain.
5183 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5185 MONO_REQ_GC_UNSAFE_MODE;
5191 MonoClass *klass = array->obj.vtable->klass;
5193 if (array->bounds == NULL) {
5194 size = mono_array_length (array);
5195 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5196 mono_error_raise_exception (&error); /* FIXME don't raise here */
5198 size *= mono_array_element_size (klass);
5200 if (klass->element_class->valuetype) {
5201 if (klass->element_class->has_references)
5202 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5204 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5206 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5209 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5214 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5215 size = mono_array_element_size (klass);
5216 for (i = 0; i < klass->rank; ++i) {
5217 sizes [i] = array->bounds [i].length;
5218 size *= array->bounds [i].length;
5219 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5221 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5222 mono_error_raise_exception (&error); /* FIXME don't raise here */
5224 if (klass->element_class->valuetype) {
5225 if (klass->element_class->has_references)
5226 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5228 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5230 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5233 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5241 * @array: the array to clone
5243 * Returns: A newly created array who is a shallow copy of @array
5246 mono_array_clone (MonoArray *array)
5248 MONO_REQ_GC_UNSAFE_MODE;
5250 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5253 /* helper macros to check for overflow when calculating the size of arrays */
5254 #ifdef MONO_BIG_ARRAYS
5255 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5256 #define MYGUINT_MAX MYGUINT64_MAX
5257 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5258 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5259 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5260 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5261 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5263 #define MYGUINT32_MAX 4294967295U
5264 #define MYGUINT_MAX MYGUINT32_MAX
5265 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5266 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5267 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5268 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5269 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5273 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5275 MONO_REQ_GC_NEUTRAL_MODE;
5279 byte_len = mono_array_element_size (klass);
5280 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5283 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5285 byte_len += MONO_SIZEOF_MONO_ARRAY;
5293 * mono_array_new_full:
5294 * @domain: domain where the object is created
5295 * @array_class: array class
5296 * @lengths: lengths for each dimension in the array
5297 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5299 * This routine creates a new array objects with the given dimensions,
5300 * lower bounds and type.
5303 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5306 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5307 mono_error_raise_exception (&error);
5313 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5315 MONO_REQ_GC_UNSAFE_MODE;
5317 uintptr_t byte_len = 0, len, bounds_size;
5320 MonoArrayBounds *bounds;
5324 mono_error_init (error);
5326 if (!array_class->inited)
5327 mono_class_init (array_class);
5331 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5332 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5334 if (len > MONO_ARRAY_MAX_INDEX) {
5335 mono_error_set_generic_error (error, "System", "OverflowException", "");
5340 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5342 for (i = 0; i < array_class->rank; ++i) {
5343 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5344 mono_error_set_generic_error (error, "System", "OverflowException", "");
5347 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5348 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5355 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5356 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5362 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5363 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5366 byte_len = (byte_len + 3) & ~3;
5367 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5368 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5371 byte_len += bounds_size;
5374 * Following three lines almost taken from mono_object_new ():
5375 * they need to be kept in sync.
5377 vtable = mono_class_vtable_full (domain, array_class, error);
5378 return_val_if_nok (error, NULL);
5381 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5383 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5385 if (G_UNLIKELY (!o)) {
5386 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5390 array = (MonoArray*)o;
5392 bounds = array->bounds;
5395 for (i = 0; i < array_class->rank; ++i) {
5396 bounds [i].length = lengths [i];
5398 bounds [i].lower_bound = lower_bounds [i];
5407 * @domain: domain where the object is created
5408 * @eclass: element class
5409 * @n: number of array elements
5411 * This routine creates a new szarray with @n elements of type @eclass.
5414 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5416 MONO_REQ_GC_UNSAFE_MODE;
5422 ac = mono_array_class_get (eclass, 1);
5425 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5426 mono_error_raise_exception (&error); /* FIXME don't raise here */
5428 arr = mono_array_new_specific_checked (vtable, n, &error);
5429 mono_error_raise_exception (&error); /* FIXME don't raise here */
5435 * mono_array_new_specific:
5436 * @vtable: a vtable in the appropriate domain for an initialized class
5437 * @n: number of array elements
5439 * This routine is a fast alternative to mono_array_new() for code which
5440 * can be sure about the domain it operates in.
5443 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5446 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5447 mono_error_raise_exception (&error); /* FIXME don't raise here */
5453 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5455 MONO_REQ_GC_UNSAFE_MODE;
5460 mono_error_init (error);
5462 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5463 mono_error_set_generic_error (error, "System", "OverflowException", "");
5467 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5468 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5471 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5473 if (G_UNLIKELY (!o)) {
5474 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5478 return (MonoArray*)o;
5482 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5485 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5486 mono_error_raise_exception (&error);
5492 * mono_string_new_utf16:
5493 * @text: a pointer to an utf16 string
5494 * @len: the length of the string
5496 * Returns: A newly created string object which contains @text.
5499 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5501 MONO_REQ_GC_UNSAFE_MODE;
5504 MonoString *res = NULL;
5505 res = mono_string_new_utf16_checked (domain, text, len, &error);
5506 mono_error_raise_exception (&error);
5512 * mono_string_new_utf16_checked:
5513 * @text: a pointer to an utf16 string
5514 * @len: the length of the string
5515 * @error: written on error.
5517 * Returns: A newly created string object which contains @text.
5518 * On error, returns NULL and sets @error.
5521 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5523 MONO_REQ_GC_UNSAFE_MODE;
5527 mono_error_init (error);
5529 s = mono_string_new_size_checked (domain, len, error);
5531 memcpy (mono_string_chars (s), text, len * 2);
5537 * mono_string_new_utf32:
5538 * @text: a pointer to an utf32 string
5539 * @len: the length of the string
5541 * Returns: A newly created string object which contains @text.
5544 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5546 MONO_REQ_GC_UNSAFE_MODE;
5550 mono_unichar2 *utf16_output = NULL;
5551 gint32 utf16_len = 0;
5552 GError *gerror = NULL;
5553 glong items_written;
5555 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5558 g_error_free (gerror);
5560 while (utf16_output [utf16_len]) utf16_len++;
5562 s = mono_string_new_size_checked (domain, utf16_len, &error);
5563 mono_error_raise_exception (&error); /* FIXME don't raise here */
5565 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5567 g_free (utf16_output);
5573 * mono_string_new_size:
5574 * @text: a pointer to an utf16 string
5575 * @len: the length of the string
5577 * Returns: A newly created string object of @len
5580 mono_string_new_size (MonoDomain *domain, gint32 len)
5583 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5584 mono_error_raise_exception (&error);
5590 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5592 MONO_REQ_GC_UNSAFE_MODE;
5598 mono_error_init (error);
5600 /* check for overflow */
5601 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5602 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5606 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5607 g_assert (size > 0);
5609 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5612 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5614 if (G_UNLIKELY (!s)) {
5615 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5623 * mono_string_new_len:
5624 * @text: a pointer to an utf8 string
5625 * @length: number of bytes in @text to consider
5627 * Returns: A newly created string object which contains @text.
5630 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5632 MONO_REQ_GC_UNSAFE_MODE;
5635 GError *eg_error = NULL;
5636 MonoString *o = NULL;
5638 glong items_written;
5640 mono_error_init (&error);
5642 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5645 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5647 g_error_free (eg_error);
5651 mono_error_raise_exception (&error); /* FIXME don't raise here */
5657 * @text: a pointer to an utf8 string
5659 * Returns: A newly created string object which contains @text.
5661 * This function asserts if it cannot allocate a new string.
5663 * @deprecated Use mono_string_new_checked in new code.
5666 mono_string_new (MonoDomain *domain, const char *text)
5669 MonoString *res = NULL;
5670 res = mono_string_new_checked (domain, text, &error);
5671 mono_error_assert_ok (&error);
5676 * mono_string_new_checked:
5677 * @text: a pointer to an utf8 string
5678 * @merror: set on error
5680 * Returns: A newly created string object which contains @text.
5681 * On error returns NULL and sets @merror.
5684 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5686 MONO_REQ_GC_UNSAFE_MODE;
5688 GError *eg_error = NULL;
5689 MonoString *o = NULL;
5691 glong items_written;
5694 mono_error_init (error);
5698 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5701 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5703 g_error_free (eg_error);
5706 mono_error_raise_exception (error);
5708 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5713 MonoString *o = NULL;
5715 if (!g_utf8_validate (text, -1, &end)) {
5716 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5720 len = g_utf8_strlen (text, -1);
5721 o = mono_string_new_size_checked (domain, len, error);
5724 str = mono_string_chars (o);
5726 while (text < end) {
5727 *str++ = g_utf8_get_char (text);
5728 text = g_utf8_next_char (text);
5737 * mono_string_new_wrapper:
5738 * @text: pointer to utf8 characters.
5740 * Helper function to create a string object from @text in the current domain.
5743 mono_string_new_wrapper (const char *text)
5745 MONO_REQ_GC_UNSAFE_MODE;
5747 MonoDomain *domain = mono_domain_get ();
5750 return mono_string_new (domain, text);
5757 * @class: the class of the value
5758 * @value: a pointer to the unboxed data
5760 * Returns: A newly created object which contains @value.
5763 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5765 MONO_REQ_GC_UNSAFE_MODE;
5772 g_assert (klass->valuetype);
5773 if (mono_class_is_nullable (klass))
5774 return mono_nullable_box ((guint8 *)value, klass);
5776 vtable = mono_class_vtable (domain, klass);
5779 size = mono_class_instance_size (klass);
5780 res = mono_object_new_alloc_specific_checked (vtable, &error);
5781 mono_error_raise_exception (&error); /* FIXME don't raise here */
5783 size = size - sizeof (MonoObject);
5786 g_assert (size == mono_class_value_size (klass, NULL));
5787 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5789 #if NO_UNALIGNED_ACCESS
5790 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5794 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5797 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5800 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5803 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5806 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5810 if (klass->has_finalize) {
5811 mono_object_register_finalizer (res, &error);
5812 mono_error_raise_exception (&error); /* FIXME don't raise here */
5819 * @dest: destination pointer
5820 * @src: source pointer
5821 * @klass: a valuetype class
5823 * Copy a valuetype from @src to @dest. This function must be used
5824 * when @klass contains references fields.
5827 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5829 MONO_REQ_GC_UNSAFE_MODE;
5831 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5835 * mono_value_copy_array:
5836 * @dest: destination array
5837 * @dest_idx: index in the @dest array
5838 * @src: source pointer
5839 * @count: number of items
5841 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5842 * This function must be used when @klass contains references fields.
5843 * Overlap is handled.
5846 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5848 MONO_REQ_GC_UNSAFE_MODE;
5850 int size = mono_array_element_size (dest->obj.vtable->klass);
5851 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5852 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5853 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5857 * mono_object_get_domain:
5858 * @obj: object to query
5860 * Returns: the MonoDomain where the object is hosted
5863 mono_object_get_domain (MonoObject *obj)
5865 MONO_REQ_GC_UNSAFE_MODE;
5867 return mono_object_domain (obj);
5871 * mono_object_get_class:
5872 * @obj: object to query
5874 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5876 * Returns: the MonoClass of the object.
5879 mono_object_get_class (MonoObject *obj)
5881 MONO_REQ_GC_UNSAFE_MODE;
5883 return mono_object_class (obj);
5886 * mono_object_get_size:
5887 * @o: object to query
5889 * Returns: the size, in bytes, of @o
5892 mono_object_get_size (MonoObject* o)
5894 MONO_REQ_GC_UNSAFE_MODE;
5896 MonoClass* klass = mono_object_class (o);
5897 if (klass == mono_defaults.string_class) {
5898 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5899 } else if (o->vtable->rank) {
5900 MonoArray *array = (MonoArray*)o;
5901 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5902 if (array->bounds) {
5905 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5909 return mono_class_instance_size (klass);
5914 * mono_object_unbox:
5915 * @obj: object to unbox
5917 * Returns: a pointer to the start of the valuetype boxed in this
5920 * This method will assert if the object passed is not a valuetype.
5923 mono_object_unbox (MonoObject *obj)
5925 MONO_REQ_GC_UNSAFE_MODE;
5927 /* add assert for valuetypes? */
5928 g_assert (obj->vtable->klass->valuetype);
5929 return ((char*)obj) + sizeof (MonoObject);
5933 * mono_object_isinst:
5935 * @klass: a pointer to a class
5937 * Returns: @obj if @obj is derived from @klass
5940 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5942 MONO_REQ_GC_UNSAFE_MODE;
5945 mono_class_init (klass);
5947 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5948 return mono_object_isinst_mbyref (obj, klass);
5953 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5957 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5959 MONO_REQ_GC_UNSAFE_MODE;
5969 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5970 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5974 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5975 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5978 MonoClass *oklass = vt->klass;
5979 if (mono_class_is_transparent_proxy (oklass))
5980 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5982 mono_class_setup_supertypes (klass);
5983 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5986 #ifndef DISABLE_REMOTING
5987 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5989 MonoDomain *domain = mono_domain_get ();
5991 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5992 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5993 MonoMethod *im = NULL;
5996 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5998 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5999 im = mono_object_get_virtual_method (rp, im);
6002 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
6003 mono_error_raise_exception (&error); /* FIXME don't raise here */
6006 res = mono_runtime_invoke_checked (im, rp, pa, &error);
6007 mono_error_raise_exception (&error); /* FIXME don't raise here */
6009 if (*(MonoBoolean *) mono_object_unbox(res)) {
6010 /* Update the vtable of the remote type, so it can safely cast to this new type */
6011 mono_upgrade_remote_class (domain, obj, klass);
6015 #endif /* DISABLE_REMOTING */
6020 * mono_object_castclass_mbyref:
6022 * @klass: a pointer to a class
6024 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6027 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6029 MONO_REQ_GC_UNSAFE_MODE;
6031 if (!obj) return NULL;
6032 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6034 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6036 "InvalidCastException"));
6041 MonoDomain *orig_domain;
6047 str_lookup (MonoDomain *domain, gpointer user_data)
6049 MONO_REQ_GC_UNSAFE_MODE;
6051 LDStrInfo *info = (LDStrInfo *)user_data;
6052 if (info->res || domain == info->orig_domain)
6054 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6058 mono_string_get_pinned (MonoString *str, MonoError *error)
6060 MONO_REQ_GC_UNSAFE_MODE;
6062 mono_error_init (error);
6064 /* We only need to make a pinned version of a string if this is a moving GC */
6065 if (!mono_gc_is_moving ())
6069 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6070 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6072 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6073 news->length = mono_string_length (str);
6075 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6081 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6083 MONO_REQ_GC_UNSAFE_MODE;
6085 MonoGHashTable *ldstr_table;
6086 MonoString *s, *res;
6089 mono_error_init (error);
6091 domain = ((MonoObject *)str)->vtable->domain;
6092 ldstr_table = domain->ldstr_table;
6094 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6100 /* Allocate outside the lock */
6102 s = mono_string_get_pinned (str, error);
6103 return_val_if_nok (error, NULL);
6106 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6111 mono_g_hash_table_insert (ldstr_table, s, s);
6116 LDStrInfo ldstr_info;
6117 ldstr_info.orig_domain = domain;
6118 ldstr_info.ins = str;
6119 ldstr_info.res = NULL;
6121 mono_domain_foreach (str_lookup, &ldstr_info);
6122 if (ldstr_info.res) {
6124 * the string was already interned in some other domain:
6125 * intern it in the current one as well.
6127 mono_g_hash_table_insert (ldstr_table, str, str);
6137 * mono_string_is_interned:
6138 * @o: String to probe
6140 * Returns whether the string has been interned.
6143 mono_string_is_interned (MonoString *o)
6146 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6147 /* This function does not fail. */
6148 mono_error_assert_ok (&error);
6153 * mono_string_intern:
6154 * @o: String to intern
6156 * Interns the string passed.
6157 * Returns: The interned string.
6160 mono_string_intern (MonoString *str)
6163 MonoString *result = mono_string_intern_checked (str, &error);
6164 mono_error_assert_ok (&error);
6169 * mono_string_intern_checked:
6170 * @o: String to intern
6171 * @error: set on error.
6173 * Interns the string passed.
6174 * Returns: The interned string. On failure returns NULL and sets @error
6177 mono_string_intern_checked (MonoString *str, MonoError *error)
6179 MONO_REQ_GC_UNSAFE_MODE;
6181 mono_error_init (error);
6183 return mono_string_is_interned_lookup (str, TRUE, error);
6188 * @domain: the domain where the string will be used.
6189 * @image: a metadata context
6190 * @idx: index into the user string table.
6192 * Implementation for the ldstr opcode.
6193 * Returns: a loaded string from the @image/@idx combination.
6196 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6198 MONO_REQ_GC_UNSAFE_MODE;
6200 if (image->dynamic) {
6201 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6204 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6205 return NULL; /*FIXME we should probably be raising an exception here*/
6206 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6211 * mono_ldstr_metadata_sig
6212 * @domain: the domain for the string
6213 * @sig: the signature of a metadata string
6215 * Returns: a MonoString for a string stored in the metadata
6218 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6220 MONO_REQ_GC_UNSAFE_MODE;
6223 const char *str = sig;
6224 MonoString *o, *interned;
6227 len2 = mono_metadata_decode_blob_size (str, &str);
6230 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6231 mono_error_raise_exception (&error); /* FIXME don't raise here */
6232 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6235 guint16 *p2 = (guint16*)mono_string_chars (o);
6236 for (i = 0; i < len2; ++i) {
6237 *p2 = GUINT16_FROM_LE (*p2);
6243 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6246 return interned; /* o will get garbage collected */
6248 o = mono_string_get_pinned (o, &error);
6249 mono_error_raise_exception (&error); /* FIXME don't raise here */
6252 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6254 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6264 * mono_string_to_utf8:
6265 * @s: a System.String
6267 * Returns the UTF8 representation for @s.
6268 * The resulting buffer needs to be freed with mono_free().
6270 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6273 mono_string_to_utf8 (MonoString *s)
6275 MONO_REQ_GC_UNSAFE_MODE;
6278 char *result = mono_string_to_utf8_checked (s, &error);
6280 if (!mono_error_ok (&error))
6281 mono_error_raise_exception (&error);
6286 * mono_string_to_utf8_checked:
6287 * @s: a System.String
6288 * @error: a MonoError.
6290 * Converts a MonoString to its UTF8 representation. May fail; check
6291 * @error to determine whether the conversion was successful.
6292 * The resulting buffer should be freed with mono_free().
6295 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6297 MONO_REQ_GC_UNSAFE_MODE;
6301 GError *gerror = NULL;
6303 mono_error_init (error);
6309 return g_strdup ("");
6311 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6313 mono_error_set_argument (error, "string", "%s", gerror->message);
6314 g_error_free (gerror);
6317 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6318 if (s->length > written) {
6319 /* allocate the total length and copy the part of the string that has been converted */
6320 char *as2 = (char *)g_malloc0 (s->length);
6321 memcpy (as2, as, written);
6330 * mono_string_to_utf8_ignore:
6333 * Converts a MonoString to its UTF8 representation. Will ignore
6334 * invalid surrogate pairs.
6335 * The resulting buffer should be freed with mono_free().
6339 mono_string_to_utf8_ignore (MonoString *s)
6341 MONO_REQ_GC_UNSAFE_MODE;
6350 return g_strdup ("");
6352 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6354 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6355 if (s->length > written) {
6356 /* allocate the total length and copy the part of the string that has been converted */
6357 char *as2 = (char *)g_malloc0 (s->length);
6358 memcpy (as2, as, written);
6367 * mono_string_to_utf8_image_ignore:
6368 * @s: a System.String
6370 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6373 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6375 MONO_REQ_GC_UNSAFE_MODE;
6377 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6381 * mono_string_to_utf8_mp_ignore:
6382 * @s: a System.String
6384 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6387 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6389 MONO_REQ_GC_UNSAFE_MODE;
6391 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6396 * mono_string_to_utf16:
6399 * Return an null-terminated array of the utf-16 chars
6400 * contained in @s. The result must be freed with g_free().
6401 * This is a temporary helper until our string implementation
6402 * is reworked to always include the null terminating char.
6405 mono_string_to_utf16 (MonoString *s)
6407 MONO_REQ_GC_UNSAFE_MODE;
6414 as = (char *)g_malloc ((s->length * 2) + 2);
6415 as [(s->length * 2)] = '\0';
6416 as [(s->length * 2) + 1] = '\0';
6419 return (gunichar2 *)(as);
6422 memcpy (as, mono_string_chars(s), s->length * 2);
6423 return (gunichar2 *)(as);
6427 * mono_string_to_utf32:
6430 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6431 * contained in @s. The result must be freed with g_free().
6434 mono_string_to_utf32 (MonoString *s)
6436 MONO_REQ_GC_UNSAFE_MODE;
6438 mono_unichar4 *utf32_output = NULL;
6439 GError *error = NULL;
6440 glong items_written;
6445 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6448 g_error_free (error);
6450 return utf32_output;
6454 * mono_string_from_utf16:
6455 * @data: the UTF16 string (LPWSTR) to convert
6457 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6459 * Returns: a MonoString.
6462 mono_string_from_utf16 (gunichar2 *data)
6464 MONO_REQ_GC_UNSAFE_MODE;
6467 MonoString *res = NULL;
6468 MonoDomain *domain = mono_domain_get ();
6474 while (data [len]) len++;
6476 res = mono_string_new_utf16_checked (domain, data, len, &error);
6477 mono_error_raise_exception (&error); /* FIXME don't raise here */
6482 * mono_string_from_utf32:
6483 * @data: the UTF32 string (LPWSTR) to convert
6485 * Converts a UTF32 (UCS-4)to a MonoString.
6487 * Returns: a MonoString.
6490 mono_string_from_utf32 (mono_unichar4 *data)
6492 MONO_REQ_GC_UNSAFE_MODE;
6494 MonoString* result = NULL;
6495 mono_unichar2 *utf16_output = NULL;
6496 GError *error = NULL;
6497 glong items_written;
6503 while (data [len]) len++;
6505 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6508 g_error_free (error);
6510 result = mono_string_from_utf16 (utf16_output);
6511 g_free (utf16_output);
6516 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6518 MONO_REQ_GC_UNSAFE_MODE;
6525 r = mono_string_to_utf8_ignore (s);
6527 r = mono_string_to_utf8_checked (s, error);
6528 if (!mono_error_ok (error))
6535 len = strlen (r) + 1;
6537 mp_s = (char *)mono_mempool_alloc (mp, len);
6539 mp_s = (char *)mono_image_alloc (image, len);
6541 memcpy (mp_s, r, len);
6549 * mono_string_to_utf8_image:
6550 * @s: a System.String
6552 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6555 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6557 MONO_REQ_GC_UNSAFE_MODE;
6559 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6563 * mono_string_to_utf8_mp:
6564 * @s: a System.String
6566 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6569 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6571 MONO_REQ_GC_UNSAFE_MODE;
6573 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6577 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6580 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6582 eh_callbacks = *cbs;
6585 MonoRuntimeExceptionHandlingCallbacks *
6586 mono_get_eh_callbacks (void)
6588 return &eh_callbacks;
6592 * mono_raise_exception:
6593 * @ex: exception object
6595 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6598 mono_raise_exception (MonoException *ex)
6600 MONO_REQ_GC_UNSAFE_MODE;
6603 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6604 * that will cause gcc to omit the function epilog, causing problems when
6605 * the JIT tries to walk the stack, since the return address on the stack
6606 * will point into the next function in the executable, not this one.
6608 eh_callbacks.mono_raise_exception (ex);
6612 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6614 MONO_REQ_GC_UNSAFE_MODE;
6616 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6620 * mono_wait_handle_new:
6621 * @domain: Domain where the object will be created
6622 * @handle: Handle for the wait handle
6624 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6627 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6629 MONO_REQ_GC_UNSAFE_MODE;
6632 MonoWaitHandle *res;
6633 gpointer params [1];
6634 static MonoMethod *handle_set;
6636 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6637 mono_error_raise_exception (&error); /* FIXME don't raise here */
6639 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6641 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6643 params [0] = &handle;
6645 mono_runtime_invoke_checked (handle_set, res, params, &error);
6646 mono_error_raise_exception (&error); /* FIXME don't raise here */
6652 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6654 MONO_REQ_GC_UNSAFE_MODE;
6656 static MonoClassField *f_safe_handle = NULL;
6659 if (!f_safe_handle) {
6660 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6661 g_assert (f_safe_handle);
6664 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6670 mono_runtime_capture_context (MonoDomain *domain)
6672 MONO_REQ_GC_UNSAFE_MODE;
6674 RuntimeInvokeFunction runtime_invoke;
6676 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6677 MonoMethod *method = mono_get_context_capture_method ();
6678 MonoMethod *wrapper;
6681 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6682 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6683 domain->capture_context_method = mono_compile_method (method);
6686 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6688 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6691 * mono_async_result_new:
6692 * @domain:domain where the object will be created.
6693 * @handle: wait handle.
6694 * @state: state to pass to AsyncResult
6695 * @data: C closure data.
6697 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6698 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6702 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6704 MONO_REQ_GC_UNSAFE_MODE;
6707 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6708 mono_error_raise_exception (&error); /* FIXME don't raise here */
6709 MonoObject *context = mono_runtime_capture_context (domain);
6710 /* we must capture the execution context from the original thread */
6712 MONO_OBJECT_SETREF (res, execution_context, context);
6713 /* note: result may be null if the flow is suppressed */
6716 res->data = (void **)data;
6717 MONO_OBJECT_SETREF (res, object_data, object_data);
6718 MONO_OBJECT_SETREF (res, async_state, state);
6720 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6722 res->sync_completed = FALSE;
6723 res->completed = FALSE;
6729 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6731 MONO_REQ_GC_UNSAFE_MODE;
6738 g_assert (ares->async_delegate);
6740 ac = (MonoAsyncCall*) ares->object_data;
6742 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6744 gpointer wait_event = NULL;
6746 ac->msg->exc = NULL;
6747 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6748 MONO_OBJECT_SETREF (ac, res, res);
6750 mono_monitor_enter ((MonoObject*) ares);
6751 ares->completed = 1;
6753 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6754 mono_monitor_exit ((MonoObject*) ares);
6756 if (wait_event != NULL)
6757 SetEvent (wait_event);
6759 if (ac->cb_method) {
6760 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6761 mono_error_raise_exception (&error);
6769 mono_message_init (MonoDomain *domain,
6770 MonoMethodMessage *this_obj,
6771 MonoReflectionMethod *method,
6772 MonoArray *out_args)
6774 MONO_REQ_GC_UNSAFE_MODE;
6776 static MonoClass *object_array_klass;
6777 static MonoClass *byte_array_klass;
6778 static MonoClass *string_array_klass;
6780 MonoMethodSignature *sig = mono_method_signature (method->method);
6787 if (!object_array_klass) {
6790 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6792 byte_array_klass = klass;
6794 klass = mono_array_class_get (mono_defaults.string_class, 1);
6796 string_array_klass = klass;
6798 klass = mono_array_class_get (mono_defaults.object_class, 1);
6801 mono_atomic_store_release (&object_array_klass, klass);
6804 MONO_OBJECT_SETREF (this_obj, method, method);
6806 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6807 mono_error_raise_exception (&error); /* FIXME don't raise here */
6809 MONO_OBJECT_SETREF (this_obj, args, arr);
6811 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6812 mono_error_raise_exception (&error); /* FIXME don't raise here */
6814 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6816 this_obj->async_result = NULL;
6817 this_obj->call_type = CallType_Sync;
6819 names = g_new (char *, sig->param_count);
6820 mono_method_get_param_names (method->method, (const char **) names);
6822 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6823 mono_error_raise_exception (&error); /* FIXME don't raise here */
6825 MONO_OBJECT_SETREF (this_obj, names, arr);
6827 for (i = 0; i < sig->param_count; i++) {
6828 name = mono_string_new (domain, names [i]);
6829 mono_array_setref (this_obj->names, i, name);
6833 for (i = 0, j = 0; i < sig->param_count; i++) {
6834 if (sig->params [i]->byref) {
6836 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6837 mono_array_setref (this_obj->args, i, arg);
6841 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6845 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6848 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6852 #ifndef DISABLE_REMOTING
6854 * mono_remoting_invoke:
6855 * @real_proxy: pointer to a RealProxy object
6856 * @msg: The MonoMethodMessage to execute
6857 * @exc: used to store exceptions
6858 * @out_args: used to store output arguments
6860 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6861 * IMessage interface and it is not trivial to extract results from there. So
6862 * we call an helper method PrivateInvoke instead of calling
6863 * RealProxy::Invoke() directly.
6865 * Returns: the result object.
6868 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6870 MONO_REQ_GC_UNSAFE_MODE;
6873 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6878 mono_error_init (error);
6880 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6883 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6885 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
6888 real_proxy->vtable->domain->private_invoke_method = im;
6891 pa [0] = real_proxy;
6896 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6897 return_val_if_nok (error, NULL);
6904 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6905 MonoObject **exc, MonoArray **out_args)
6907 MONO_REQ_GC_UNSAFE_MODE;
6909 static MonoClass *object_array_klass;
6913 MonoMethodSignature *sig;
6916 int i, j, outarg_count = 0;
6918 #ifndef DISABLE_REMOTING
6919 if (target && mono_object_is_transparent_proxy (target)) {
6920 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6921 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6922 target = tp->rp->unwrapped_server;
6924 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
6925 mono_error_raise_exception (&error); /* FIXME don't raise here */
6932 domain = mono_domain_get ();
6933 method = msg->method->method;
6934 sig = mono_method_signature (method);
6936 for (i = 0; i < sig->param_count; i++) {
6937 if (sig->params [i]->byref)
6941 if (!object_array_klass) {
6944 klass = mono_array_class_get (mono_defaults.object_class, 1);
6947 mono_memory_barrier ();
6948 object_array_klass = klass;
6951 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6952 mono_error_raise_exception (&error); /* FIXME don't raise here */
6954 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6957 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6959 for (i = 0, j = 0; i < sig->param_count; i++) {
6960 if (sig->params [i]->byref) {
6962 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6963 mono_array_setref (*out_args, j, arg);
6972 * mono_object_to_string:
6974 * @exc: Any exception thrown by ToString (). May be NULL.
6976 * Returns: the result of calling ToString () on an object.
6979 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6981 MONO_REQ_GC_UNSAFE_MODE;
6983 static MonoMethod *to_string = NULL;
6992 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6994 method = mono_object_get_virtual_method (obj, to_string);
6996 // Unbox value type if needed
6997 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6998 target = mono_object_unbox (obj);
7002 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7003 if (*exc == NULL && !mono_error_ok (&error))
7004 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7006 mono_error_cleanup (&error);
7008 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7009 mono_error_raise_exception (&error); /* FIXME don't raise here */
7016 * mono_print_unhandled_exception:
7017 * @exc: The exception
7019 * Prints the unhandled exception.
7022 mono_print_unhandled_exception (MonoObject *exc)
7024 MONO_REQ_GC_UNSAFE_MODE;
7027 char *message = (char*)"";
7028 gboolean free_message = FALSE;
7031 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7032 message = g_strdup ("OutOfMemoryException");
7033 free_message = TRUE;
7034 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7035 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7036 free_message = TRUE;
7039 if (((MonoException*)exc)->native_trace_ips) {
7040 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7041 free_message = TRUE;
7043 MonoObject *other_exc = NULL;
7044 str = mono_object_to_string (exc, &other_exc);
7046 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7047 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7049 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7050 original_backtrace, nested_backtrace);
7052 g_free (original_backtrace);
7053 g_free (nested_backtrace);
7054 free_message = TRUE;
7056 message = mono_string_to_utf8_checked (str, &error);
7057 if (!mono_error_ok (&error)) {
7058 mono_error_cleanup (&error);
7059 message = (char *) "";
7061 free_message = TRUE;
7068 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7069 * exc->vtable->klass->name, message);
7071 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7078 * mono_delegate_ctor:
7079 * @this: pointer to an uninitialized delegate object
7080 * @target: target object
7081 * @addr: pointer to native code
7084 * Initialize a delegate and sets a specific method, not the one
7085 * associated with addr. This is useful when sharing generic code.
7086 * In that case addr will most probably not be associated with the
7087 * correct instantiation of the method.
7090 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7092 MONO_REQ_GC_UNSAFE_MODE;
7094 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7096 g_assert (this_obj);
7099 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7102 delegate->method = method;
7104 mono_stats.delegate_creations++;
7106 #ifndef DISABLE_REMOTING
7107 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7109 method = mono_marshal_get_remoting_invoke (method);
7110 delegate->method_ptr = mono_compile_method (method);
7111 MONO_OBJECT_SETREF (delegate, target, target);
7115 delegate->method_ptr = addr;
7116 MONO_OBJECT_SETREF (delegate, target, target);
7119 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7120 if (callbacks.init_delegate)
7121 callbacks.init_delegate (delegate);
7125 * mono_delegate_ctor:
7126 * @this: pointer to an uninitialized delegate object
7127 * @target: target object
7128 * @addr: pointer to native code
7130 * This is used to initialize a delegate.
7133 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7135 MONO_REQ_GC_UNSAFE_MODE;
7137 MonoDomain *domain = mono_domain_get ();
7139 MonoMethod *method = NULL;
7143 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7145 if (!ji && domain != mono_get_root_domain ())
7146 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7148 method = mono_jit_info_get_method (ji);
7149 g_assert (!method->klass->generic_container);
7152 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7156 * mono_method_call_message_new:
7157 * @method: method to encapsulate
7158 * @params: parameters to the method
7159 * @invoke: optional, delegate invoke.
7160 * @cb: async callback delegate.
7161 * @state: state passed to the async callback.
7163 * Translates arguments pointers into a MonoMethodMessage.
7166 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7167 MonoDelegate **cb, MonoObject **state)
7169 MONO_REQ_GC_UNSAFE_MODE;
7173 MonoDomain *domain = mono_domain_get ();
7174 MonoMethodSignature *sig = mono_method_signature (method);
7175 MonoMethodMessage *msg;
7178 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7179 mono_error_raise_exception (&error); /* FIXME don't raise here */
7182 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7183 mono_error_raise_exception (&error); /* FIXME don't raise here */
7184 mono_message_init (domain, msg, rm, NULL);
7185 count = sig->param_count - 2;
7187 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7188 mono_error_raise_exception (&error); /* FIXME don't raise here */
7189 mono_message_init (domain, msg, rm, NULL);
7190 count = sig->param_count;
7193 for (i = 0; i < count; i++) {
7198 if (sig->params [i]->byref)
7199 vpos = *((gpointer *)params [i]);
7203 klass = mono_class_from_mono_type (sig->params [i]);
7205 if (klass->valuetype)
7206 arg = mono_value_box (domain, klass, vpos);
7208 arg = *((MonoObject **)vpos);
7210 mono_array_setref (msg->args, i, arg);
7213 if (cb != NULL && state != NULL) {
7214 *cb = *((MonoDelegate **)params [i]);
7216 *state = *((MonoObject **)params [i]);
7223 * mono_method_return_message_restore:
7225 * Restore results from message based processing back to arguments pointers
7228 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7230 MONO_REQ_GC_UNSAFE_MODE;
7232 MonoMethodSignature *sig = mono_method_signature (method);
7233 int i, j, type, size, out_len;
7235 if (out_args == NULL)
7237 out_len = mono_array_length (out_args);
7241 for (i = 0, j = 0; i < sig->param_count; i++) {
7242 MonoType *pt = sig->params [i];
7247 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7249 arg = (char *)mono_array_get (out_args, gpointer, j);
7252 g_assert (type != MONO_TYPE_VOID);
7254 if (MONO_TYPE_IS_REFERENCE (pt)) {
7255 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7258 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7259 size = mono_class_value_size (klass, NULL);
7260 if (klass->has_references)
7261 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7263 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7265 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7266 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7275 #ifndef DISABLE_REMOTING
7278 * mono_load_remote_field:
7279 * @this: pointer to an object
7280 * @klass: klass of the object containing @field
7281 * @field: the field to load
7282 * @res: a storage to store the result
7284 * This method is called by the runtime on attempts to load fields of
7285 * transparent proxy objects. @this points to such TP, @klass is the class of
7286 * the object containing @field. @res is a storage location which can be
7287 * used to store the result.
7289 * Returns: an address pointing to the value of field.
7292 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7294 MONO_REQ_GC_UNSAFE_MODE;
7298 static MonoMethod *getter = NULL;
7299 MonoDomain *domain = mono_domain_get ();
7300 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7301 MonoClass *field_class;
7302 MonoMethodMessage *msg;
7303 MonoArray *out_args;
7307 g_assert (mono_object_is_transparent_proxy (this_obj));
7308 g_assert (res != NULL);
7310 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7311 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7316 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7318 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7321 field_class = mono_class_from_mono_type (field->type);
7323 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7324 mono_error_raise_exception (&error); /* FIXME don't raise here */
7325 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7326 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7327 mono_error_raise_exception (&error); /* FIXME don't raise here */
7328 mono_message_init (domain, msg, rm, out_args);
7330 full_name = mono_type_get_full_name (klass);
7331 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7332 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7335 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7336 mono_error_raise_exception (&error); /* FIXME don't raise here */
7338 if (exc) mono_raise_exception ((MonoException *)exc);
7340 if (mono_array_length (out_args) == 0)
7343 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7345 if (field_class->valuetype) {
7346 return ((char *)*res) + sizeof (MonoObject);
7352 * mono_load_remote_field_new:
7357 * Missing documentation.
7360 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7362 MONO_REQ_GC_UNSAFE_MODE;
7366 static MonoMethod *getter = NULL;
7367 MonoDomain *domain = mono_domain_get ();
7368 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7369 MonoClass *field_class;
7370 MonoMethodMessage *msg;
7371 MonoArray *out_args;
7372 MonoObject *exc, *res;
7375 g_assert (mono_object_is_transparent_proxy (this_obj));
7377 field_class = mono_class_from_mono_type (field->type);
7379 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7381 if (field_class->valuetype) {
7382 res = mono_object_new_checked (domain, field_class, &error);
7383 mono_error_raise_exception (&error); /* FIXME don't raise here */
7384 val = ((gchar *) res) + sizeof (MonoObject);
7388 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7393 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7395 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7398 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7399 mono_error_raise_exception (&error); /* FIXME don't raise here */
7400 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7402 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7403 mono_error_raise_exception (&error); /* FIXME don't raise here */
7404 mono_message_init (domain, msg, rm, out_args);
7406 full_name = mono_type_get_full_name (klass);
7407 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7408 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7411 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7412 mono_error_raise_exception (&error); /* FIXME don't raise here */
7414 if (exc) mono_raise_exception ((MonoException *)exc);
7416 if (mono_array_length (out_args) == 0)
7419 res = mono_array_get (out_args, MonoObject *, 0);
7425 * mono_store_remote_field:
7426 * @this_obj: pointer to an object
7427 * @klass: klass of the object containing @field
7428 * @field: the field to load
7429 * @val: the value/object to store
7431 * This method is called by the runtime on attempts to store fields of
7432 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7433 * the object containing @field. @val is the new value to store in @field.
7436 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7438 MONO_REQ_GC_UNSAFE_MODE;
7442 static MonoMethod *setter = NULL;
7443 MonoDomain *domain = mono_domain_get ();
7444 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7445 MonoClass *field_class;
7446 MonoMethodMessage *msg;
7447 MonoArray *out_args;
7452 g_assert (mono_object_is_transparent_proxy (this_obj));
7454 field_class = mono_class_from_mono_type (field->type);
7456 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7457 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7458 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7463 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7465 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7468 if (field_class->valuetype)
7469 arg = mono_value_box (domain, field_class, val);
7471 arg = *((MonoObject **)val);
7474 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7475 mono_error_raise_exception (&error); /* FIXME don't raise here */
7476 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7477 mono_error_raise_exception (&error); /* FIXME don't raise here */
7478 mono_message_init (domain, msg, rm, NULL);
7480 full_name = mono_type_get_full_name (klass);
7481 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7482 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7483 mono_array_setref (msg->args, 2, arg);
7486 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7487 mono_error_raise_exception (&error); /* FIXME don't raise here */
7489 if (exc) mono_raise_exception ((MonoException *)exc);
7493 * mono_store_remote_field_new:
7499 * Missing documentation
7502 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7504 MONO_REQ_GC_UNSAFE_MODE;
7508 static MonoMethod *setter = NULL;
7509 MonoDomain *domain = mono_domain_get ();
7510 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7511 MonoClass *field_class;
7512 MonoMethodMessage *msg;
7513 MonoArray *out_args;
7517 g_assert (mono_object_is_transparent_proxy (this_obj));
7519 field_class = mono_class_from_mono_type (field->type);
7521 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7522 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7523 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7528 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7530 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7533 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7534 mono_error_raise_exception (&error); /* FIXME don't raise here */
7535 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7536 mono_error_raise_exception (&error); /* FIXME don't raise here */
7537 mono_message_init (domain, msg, rm, NULL);
7539 full_name = mono_type_get_full_name (klass);
7540 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7541 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7542 mono_array_setref (msg->args, 2, arg);
7545 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7546 mono_error_raise_exception (&error); /* FIXME don't raise here */
7548 if (exc) mono_raise_exception ((MonoException *)exc);
7553 * mono_create_ftnptr:
7555 * Given a function address, create a function descriptor for it.
7556 * This is only needed on some platforms.
7559 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7561 return callbacks.create_ftnptr (domain, addr);
7565 * mono_get_addr_from_ftnptr:
7567 * Given a pointer to a function descriptor, return the function address.
7568 * This is only needed on some platforms.
7571 mono_get_addr_from_ftnptr (gpointer descr)
7573 return callbacks.get_addr_from_ftnptr (descr);
7577 * mono_string_chars:
7580 * Returns a pointer to the UCS16 characters stored in the MonoString
7583 mono_string_chars (MonoString *s)
7585 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7591 * mono_string_length:
7594 * Returns the lenght in characters of the string
7597 mono_string_length (MonoString *s)
7599 MONO_REQ_GC_UNSAFE_MODE;
7605 * mono_array_length:
7606 * @array: a MonoArray*
7608 * Returns the total number of elements in the array. This works for
7609 * both vectors and multidimensional arrays.
7612 mono_array_length (MonoArray *array)
7614 MONO_REQ_GC_UNSAFE_MODE;
7616 return array->max_length;
7620 * mono_array_addr_with_size:
7621 * @array: a MonoArray*
7622 * @size: size of the array elements
7623 * @idx: index into the array
7625 * Use this function to obtain the address for the @idx item on the
7626 * @array containing elements of size @size.
7628 * This method performs no bounds checking or type checking.
7630 * Returns the address of the @idx element in the array.
7633 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7635 MONO_REQ_GC_UNSAFE_MODE;
7637 return ((char*)(array)->vector) + size * idx;
7642 mono_glist_to_array (GList *list, MonoClass *eclass)
7644 MonoDomain *domain = mono_domain_get ();
7651 len = g_list_length (list);
7652 res = mono_array_new (domain, eclass, len);
7654 for (i = 0; list; list = list->next, i++)
7655 mono_array_set (res, gpointer, i, list->data);
7662 * The following section is purely to declare prototypes and
7663 * document the API, as these C files are processed by our
7669 * @array: array to alter
7670 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7671 * @index: index into the array
7672 * @value: value to set
7674 * Value Type version: This sets the @index's element of the @array
7675 * with elements of size sizeof(type) to the provided @value.
7677 * This macro does not attempt to perform type checking or bounds checking.
7679 * Use this to set value types in a `MonoArray`.
7681 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7686 * mono_array_setref:
7687 * @array: array to alter
7688 * @index: index into the array
7689 * @value: value to set
7691 * Reference Type version: This sets the @index's element of the
7692 * @array with elements of size sizeof(type) to the provided @value.
7694 * This macro does not attempt to perform type checking or bounds checking.
7696 * Use this to reference types in a `MonoArray`.
7698 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7704 * @array: array on which to operate on
7705 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7706 * @index: index into the array
7708 * Use this macro to retrieve the @index element of an @array and
7709 * extract the value assuming that the elements of the array match
7710 * the provided type value.
7712 * This method can be used with both arrays holding value types and
7713 * reference types. For reference types, the @type parameter should
7714 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7716 * This macro does not attempt to perform type checking or bounds checking.
7718 * Returns: The element at the @index position in the @array.
7720 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)