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)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/metadata/w32event.h>
45 #include <mono/utils/strenc.h>
46 #include <mono/utils/mono-counters.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/checked-build.h>
50 #include <mono/utils/mono-threads.h>
51 #include <mono/utils/mono-threads-coop.h>
52 #include "cominterop.h"
55 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61 free_main_args (void);
64 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 /* Class lazy loading functions */
67 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
68 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
69 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
70 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
71 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
74 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
75 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
76 static mono_mutex_t ldstr_section;
80 * mono_runtime_object_init:
81 * @this_obj: the object to initialize
83 * This function calls the zero-argument constructor (which must
84 * exist) for the given object.
87 mono_runtime_object_init (MonoObject *this_obj)
90 mono_runtime_object_init_checked (this_obj, &error);
91 mono_error_assert_ok (&error);
95 * mono_runtime_object_init_checked:
96 * @this_obj: the object to initialize
97 * @error: set on error.
99 * This function calls the zero-argument constructor (which must
100 * exist) for the given object and returns TRUE on success, or FALSE
101 * on error and sets @error.
104 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
106 MONO_REQ_GC_UNSAFE_MODE;
108 MonoMethod *method = NULL;
109 MonoClass *klass = this_obj->vtable->klass;
111 mono_error_init (error);
112 method = mono_class_get_method_from_name (klass, ".ctor", 0);
114 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
116 if (method->klass->valuetype)
117 this_obj = (MonoObject *)mono_object_unbox (this_obj);
119 mono_runtime_invoke_checked (method, this_obj, NULL, error);
120 return is_ok (error);
123 /* The pseudo algorithm for type initialization from the spec
124 Note it doesn't say anything about domains - only threads.
126 2. If the type is initialized you are done.
127 2.1. If the type is not yet initialized, try to take an
129 2.2. If successful, record this thread as responsible for
130 initializing the type and proceed to step 2.3.
131 2.2.1. If not, see whether this thread or any thread
132 waiting for this thread to complete already holds the lock.
133 2.2.2. If so, return since blocking would create a deadlock. This thread
134 will now see an incompletely initialized state for the type,
135 but no deadlock will arise.
136 2.2.3 If not, block until the type is initialized then return.
137 2.3 Initialize the parent type and then all interfaces implemented
139 2.4 Execute the type initialization code for this type.
140 2.5 Mark the type as initialized, release the initialization lock,
141 awaken any threads waiting for this type to be initialized,
148 MonoNativeThreadId initializing_tid;
149 guint32 waiting_count;
151 MonoCoopMutex initialization_section;
152 } TypeInitializationLock;
154 /* for locking access to type_initialization_hash and blocked_thread_hash */
155 static MonoCoopMutex type_initialization_section;
158 mono_type_initialization_lock (void)
160 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
161 mono_coop_mutex_lock (&type_initialization_section);
165 mono_type_initialization_unlock (void)
167 mono_coop_mutex_unlock (&type_initialization_section);
171 mono_type_init_lock (TypeInitializationLock *lock)
173 MONO_REQ_GC_NEUTRAL_MODE;
175 mono_coop_mutex_lock (&lock->initialization_section);
179 mono_type_init_unlock (TypeInitializationLock *lock)
181 mono_coop_mutex_unlock (&lock->initialization_section);
184 /* from vtable to lock */
185 static GHashTable *type_initialization_hash;
187 /* from thread id to thread id being waited on */
188 static GHashTable *blocked_thread_hash;
191 static MonoThread *main_thread;
193 /* Functions supplied by the runtime */
194 static MonoRuntimeCallbacks callbacks;
197 * mono_thread_set_main:
198 * @thread: thread to set as the main thread
200 * This function can be used to instruct the runtime to treat @thread
201 * as the main thread, ie, the thread that would normally execute the Main()
202 * method. This basically means that at the end of @thread, the runtime will
203 * wait for the existing foreground threads to quit and other such details.
206 mono_thread_set_main (MonoThread *thread)
208 MONO_REQ_GC_UNSAFE_MODE;
210 static gboolean registered = FALSE;
213 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
217 main_thread = thread;
221 mono_thread_get_main (void)
223 MONO_REQ_GC_UNSAFE_MODE;
229 mono_type_initialization_init (void)
231 mono_coop_mutex_init_recursive (&type_initialization_section);
232 type_initialization_hash = g_hash_table_new (NULL, NULL);
233 blocked_thread_hash = g_hash_table_new (NULL, NULL);
234 mono_os_mutex_init_recursive (&ldstr_section);
238 mono_type_initialization_cleanup (void)
241 /* This is causing race conditions with
242 * mono_release_type_locks
244 mono_coop_mutex_destroy (&type_initialization_section);
245 g_hash_table_destroy (type_initialization_hash);
246 type_initialization_hash = NULL;
248 mono_os_mutex_destroy (&ldstr_section);
249 g_hash_table_destroy (blocked_thread_hash);
250 blocked_thread_hash = NULL;
256 * get_type_init_exception_for_vtable:
258 * Return the stored type initialization exception for VTABLE.
260 static MonoException*
261 get_type_init_exception_for_vtable (MonoVTable *vtable)
263 MONO_REQ_GC_UNSAFE_MODE;
266 MonoDomain *domain = vtable->domain;
267 MonoClass *klass = vtable->klass;
271 if (!vtable->init_failed)
272 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
275 * If the initializing thread was rudely aborted, the exception is not stored
279 mono_domain_lock (domain);
280 if (domain->type_init_exception_hash)
281 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
282 mono_domain_unlock (domain);
285 if (klass->name_space && *klass->name_space)
286 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
288 full_name = g_strdup (klass->name);
289 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
291 return_val_if_nok (&error, NULL);
298 * mono_runtime_class_init:
299 * @vtable: vtable that needs to be initialized
301 * This routine calls the class constructor for @vtable.
304 mono_runtime_class_init (MonoVTable *vtable)
306 MONO_REQ_GC_UNSAFE_MODE;
309 mono_runtime_class_init_full (vtable, &error);
310 mono_error_assert_ok (&error);
314 * mono_runtime_class_init_full:
315 * @vtable that neeeds to be initialized
316 * @error set on error
318 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
322 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
324 MONO_REQ_GC_UNSAFE_MODE;
326 MonoMethod *method = NULL;
329 MonoDomain *domain = vtable->domain;
330 TypeInitializationLock *lock;
331 MonoNativeThreadId tid;
332 int do_initialization = 0;
333 MonoDomain *last_domain = NULL;
334 MonoException * pending_tae = NULL;
336 mono_error_init (error);
338 if (vtable->initialized)
341 klass = vtable->klass;
343 if (!klass->image->checked_module_cctor) {
344 mono_image_check_for_module_cctor (klass->image);
345 if (klass->image->has_module_cctor) {
346 MonoClass *module_klass;
347 MonoVTable *module_vtable;
349 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
354 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
357 if (!mono_runtime_class_init_full (module_vtable, error))
361 method = mono_class_get_cctor (klass);
363 vtable->initialized = 1;
367 tid = mono_native_thread_id_get ();
369 mono_type_initialization_lock ();
370 /* double check... */
371 if (vtable->initialized) {
372 mono_type_initialization_unlock ();
375 if (vtable->init_failed) {
376 mono_type_initialization_unlock ();
378 /* The type initialization already failed once, rethrow the same exception */
379 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
382 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
384 /* This thread will get to do the initialization */
385 if (mono_domain_get () != domain) {
386 /* Transfer into the target domain */
387 last_domain = mono_domain_get ();
388 if (!mono_domain_set (domain, FALSE)) {
389 vtable->initialized = 1;
390 mono_type_initialization_unlock ();
391 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
395 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
396 mono_coop_mutex_init_recursive (&lock->initialization_section);
397 lock->initializing_tid = tid;
398 lock->waiting_count = 1;
400 /* grab the vtable lock while this thread still owns type_initialization_section */
401 /* This is why type_initialization_lock needs to enter blocking mode */
402 mono_type_init_lock (lock);
403 g_hash_table_insert (type_initialization_hash, vtable, lock);
404 do_initialization = 1;
407 TypeInitializationLock *pending_lock;
409 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
410 mono_type_initialization_unlock ();
413 /* see if the thread doing the initialization is already blocked on this thread */
414 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
415 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
416 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
417 if (!pending_lock->done) {
418 mono_type_initialization_unlock ();
421 /* the thread doing the initialization is blocked on this thread,
422 but on a lock that has already been freed. It just hasn't got
427 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
429 ++lock->waiting_count;
430 /* record the fact that we are waiting on the initializing thread */
431 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
433 mono_type_initialization_unlock ();
435 if (do_initialization) {
436 MonoException *exc = NULL;
438 mono_threads_begin_abort_protected_block ();
439 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
440 mono_threads_end_abort_protected_block ();
442 //exception extracted, error will be set to the right value later
443 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
444 exc = mono_error_convert_to_exception (error);
446 mono_error_cleanup (error);
448 mono_error_init (error);
450 /* If the initialization failed, mark the class as unusable. */
451 /* Avoid infinite loops */
453 (klass->image == mono_defaults.corlib &&
454 !strcmp (klass->name_space, "System") &&
455 !strcmp (klass->name, "TypeInitializationException")))) {
456 vtable->init_failed = 1;
458 if (klass->name_space && *klass->name_space)
459 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
461 full_name = g_strdup (klass->name);
463 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
466 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
469 * Store the exception object so it could be thrown on subsequent
472 mono_domain_lock (domain);
473 if (!domain->type_init_exception_hash)
474 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");
475 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
476 mono_domain_unlock (domain);
480 mono_domain_set (last_domain, TRUE);
482 mono_type_init_unlock (lock);
483 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
485 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
487 pending_tae = mono_thread_try_resume_interruption ();
489 /* this just blocks until the initializing thread is done */
490 mono_type_init_lock (lock);
491 mono_type_init_unlock (lock);
494 mono_type_initialization_lock ();
495 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
496 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
497 --lock->waiting_count;
498 if (lock->waiting_count == 0) {
499 mono_coop_mutex_destroy (&lock->initialization_section);
500 g_hash_table_remove (type_initialization_hash, vtable);
503 mono_memory_barrier ();
504 if (!vtable->init_failed)
505 vtable->initialized = 1;
506 mono_type_initialization_unlock ();
510 mono_error_set_exception_instance (error, pending_tae);
511 else if (vtable->init_failed) {
512 /* Either we were the initializing thread or we waited for the initialization */
513 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
520 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
522 MONO_REQ_GC_NEUTRAL_MODE;
524 MonoVTable *vtable = (MonoVTable*)key;
526 TypeInitializationLock *lock = (TypeInitializationLock*) value;
527 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
530 * Have to set this since it cannot be set by the normal code in
531 * mono_runtime_class_init (). In this case, the exception object is not stored,
532 * and get_type_init_exception_for_class () needs to be aware of this.
534 vtable->init_failed = 1;
535 mono_type_init_unlock (lock);
536 --lock->waiting_count;
537 if (lock->waiting_count == 0) {
538 mono_coop_mutex_destroy (&lock->initialization_section);
547 mono_release_type_locks (MonoInternalThread *thread)
549 MONO_REQ_GC_UNSAFE_MODE;
551 mono_type_initialization_lock ();
552 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
553 mono_type_initialization_unlock ();
556 #ifndef DISABLE_REMOTING
559 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
561 if (!callbacks.create_remoting_trampoline)
562 g_error ("remoting not installed");
563 return callbacks.create_remoting_trampoline (domain, method, target, error);
568 static MonoImtTrampolineBuilder imt_trampoline_builder;
569 static gboolean always_build_imt_trampolines;
571 #if (MONO_IMT_SIZE > 32)
572 #error "MONO_IMT_SIZE cannot be larger than 32"
576 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
578 memcpy (&callbacks, cbs, sizeof (*cbs));
581 MonoRuntimeCallbacks*
582 mono_get_runtime_callbacks (void)
588 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
590 imt_trampoline_builder = func;
594 mono_set_always_build_imt_trampolines (gboolean value)
596 always_build_imt_trampolines = value;
600 * mono_compile_method:
601 * @method: The method to compile.
603 * This JIT-compiles the method, and returns the pointer to the native code
607 mono_compile_method (MonoMethod *method)
610 gpointer result = mono_compile_method_checked (method, &error);
611 mono_error_cleanup (&error);
616 * mono_compile_method:
617 * @method: The method to compile.
618 * @error: set on error.
620 * This JIT-compiles the method, and returns the pointer to the native code
621 * produced. On failure returns NULL and sets @error.
624 mono_compile_method_checked (MonoMethod *method, MonoError *error)
628 MONO_REQ_GC_NEUTRAL_MODE
630 mono_error_init (error);
632 g_assert (callbacks.compile_method);
633 res = callbacks.compile_method (method, error);
638 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
642 MONO_REQ_GC_NEUTRAL_MODE;
644 mono_error_init (error);
645 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
650 mono_runtime_create_delegate_trampoline (MonoClass *klass)
652 MONO_REQ_GC_NEUTRAL_MODE
654 g_assert (callbacks.create_delegate_trampoline);
655 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
659 * mono_runtime_free_method:
660 * @domain; domain where the method is hosted
661 * @method: method to release
663 * This routine is invoked to free the resources associated with
664 * a method that has been JIT compiled. This is used to discard
665 * methods that were used only temporarily (for example, used in marshalling)
669 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
671 MONO_REQ_GC_NEUTRAL_MODE
673 if (callbacks.free_method)
674 callbacks.free_method (domain, method);
676 mono_method_clear_object (domain, method);
678 mono_free_method (method);
682 * The vtables in the root appdomain are assumed to be reachable by other
683 * roots, and we don't use typed allocation in the other domains.
686 /* The sync block is no longer a GC pointer */
687 #define GC_HEADER_BITMAP (0)
689 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
692 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
694 MONO_REQ_GC_NEUTRAL_MODE;
696 MonoClassField *field;
702 max_size = mono_class_data_size (klass) / sizeof (gpointer);
704 max_size = klass->instance_size / sizeof (gpointer);
705 if (max_size > size) {
706 g_assert (offset <= 0);
707 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
712 /*An Ephemeron cannot be marked by sgen*/
713 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
715 memset (bitmap, 0, size / 8);
720 for (p = klass; p != NULL; p = p->parent) {
721 gpointer iter = NULL;
722 while ((field = mono_class_get_fields (p, &iter))) {
726 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
728 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
731 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
734 /* FIXME: should not happen, flag as type load error */
735 if (field->type->byref)
738 if (static_fields && field->offset == -1)
742 pos = field->offset / sizeof (gpointer);
745 type = mono_type_get_underlying_type (field->type);
746 switch (type->type) {
749 case MONO_TYPE_FNPTR:
751 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
756 if (klass->image != mono_defaults.corlib)
759 case MONO_TYPE_STRING:
760 case MONO_TYPE_SZARRAY:
761 case MONO_TYPE_CLASS:
762 case MONO_TYPE_OBJECT:
763 case MONO_TYPE_ARRAY:
764 g_assert ((field->offset % sizeof(gpointer)) == 0);
766 g_assert (pos < size || pos <= max_size);
767 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
768 *max_set = MAX (*max_set, pos);
770 case MONO_TYPE_GENERICINST:
771 if (!mono_type_generic_inst_is_valuetype (type)) {
772 g_assert ((field->offset % sizeof(gpointer)) == 0);
774 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
775 *max_set = MAX (*max_set, pos);
780 case MONO_TYPE_VALUETYPE: {
781 MonoClass *fclass = mono_class_from_mono_type (field->type);
782 if (fclass->has_references) {
783 /* remove the object header */
784 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
798 case MONO_TYPE_BOOLEAN:
802 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
813 * mono_class_compute_bitmap:
815 * Mono internal function to compute a bitmap of reference fields in a class.
818 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
820 MONO_REQ_GC_NEUTRAL_MODE;
822 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
827 * similar to the above, but sets the bits in the bitmap for any non-ref field
828 * and ignores static fields
831 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
833 MonoClassField *field;
838 max_size = class->instance_size / sizeof (gpointer);
839 if (max_size >= size) {
840 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
843 for (p = class; p != NULL; p = p->parent) {
844 gpointer iter = NULL;
845 while ((field = mono_class_get_fields (p, &iter))) {
848 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
850 /* FIXME: should not happen, flag as type load error */
851 if (field->type->byref)
854 pos = field->offset / sizeof (gpointer);
857 type = mono_type_get_underlying_type (field->type);
858 switch (type->type) {
859 #if SIZEOF_VOID_P == 8
863 case MONO_TYPE_FNPTR:
868 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
869 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
870 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
873 #if SIZEOF_VOID_P == 4
877 case MONO_TYPE_FNPTR:
882 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
883 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
884 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
890 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
891 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
892 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
895 case MONO_TYPE_BOOLEAN:
898 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
900 case MONO_TYPE_STRING:
901 case MONO_TYPE_SZARRAY:
902 case MONO_TYPE_CLASS:
903 case MONO_TYPE_OBJECT:
904 case MONO_TYPE_ARRAY:
906 case MONO_TYPE_GENERICINST:
907 if (!mono_type_generic_inst_is_valuetype (type)) {
912 case MONO_TYPE_VALUETYPE: {
913 MonoClass *fclass = mono_class_from_mono_type (field->type);
914 /* remove the object header */
915 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
919 g_assert_not_reached ();
928 * mono_class_insecure_overlapping:
929 * check if a class with explicit layout has references and non-references
930 * fields overlapping.
932 * Returns: TRUE if it is insecure to load the type.
935 mono_class_insecure_overlapping (MonoClass *klass)
939 gsize default_bitmap [4] = {0};
941 gsize default_nrbitmap [4] = {0};
942 int i, insecure = FALSE;
945 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
946 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
948 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
949 int idx = i % (sizeof (bitmap [0]) * 8);
950 if (bitmap [idx] & nrbitmap [idx]) {
955 if (bitmap != default_bitmap)
957 if (nrbitmap != default_nrbitmap)
960 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
968 ves_icall_string_alloc (int length)
971 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
972 mono_error_set_pending_exception (&error);
978 mono_class_compute_gc_descriptor (MonoClass *klass)
980 MONO_REQ_GC_NEUTRAL_MODE;
984 gsize default_bitmap [4] = {0};
985 static gboolean gcj_inited = FALSE;
990 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
991 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
994 mono_loader_unlock ();
998 mono_class_init (klass);
1000 if (klass->gc_descr_inited)
1003 klass->gc_descr_inited = TRUE;
1004 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1006 bitmap = default_bitmap;
1007 if (klass == mono_defaults.string_class) {
1008 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1009 } else if (klass->rank) {
1010 mono_class_compute_gc_descriptor (klass->element_class);
1011 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1013 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1014 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1015 class->name_space, class->name);*/
1017 /* remove the object header */
1018 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1019 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));
1020 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1021 class->name_space, class->name);*/
1022 if (bitmap != default_bitmap)
1026 /*static int count = 0;
1029 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1030 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1032 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1033 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1035 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1036 if (bitmap != default_bitmap)
1042 * field_is_special_static:
1043 * @fklass: The MonoClass to look up.
1044 * @field: The MonoClassField describing the field.
1046 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1047 * SPECIAL_STATIC_NONE otherwise.
1050 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1052 MONO_REQ_GC_NEUTRAL_MODE;
1055 MonoCustomAttrInfo *ainfo;
1057 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1058 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1061 for (i = 0; i < ainfo->num_attrs; ++i) {
1062 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1063 if (klass->image == mono_defaults.corlib) {
1064 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1065 mono_custom_attrs_free (ainfo);
1066 return SPECIAL_STATIC_THREAD;
1068 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1069 mono_custom_attrs_free (ainfo);
1070 return SPECIAL_STATIC_CONTEXT;
1074 mono_custom_attrs_free (ainfo);
1075 return SPECIAL_STATIC_NONE;
1078 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1079 #define mix(a,b,c) { \
1080 a -= c; a ^= rot(c, 4); c += b; \
1081 b -= a; b ^= rot(a, 6); a += c; \
1082 c -= b; c ^= rot(b, 8); b += a; \
1083 a -= c; a ^= rot(c,16); c += b; \
1084 b -= a; b ^= rot(a,19); a += c; \
1085 c -= b; c ^= rot(b, 4); b += a; \
1087 #define final(a,b,c) { \
1088 c ^= b; c -= rot(b,14); \
1089 a ^= c; a -= rot(c,11); \
1090 b ^= a; b -= rot(a,25); \
1091 c ^= b; c -= rot(b,16); \
1092 a ^= c; a -= rot(c,4); \
1093 b ^= a; b -= rot(a,14); \
1094 c ^= b; c -= rot(b,24); \
1098 * mono_method_get_imt_slot:
1100 * The IMT slot is embedded into AOTed code, so this must return the same value
1101 * for the same method across all executions. This means:
1102 * - pointers shouldn't be used as hash values.
1103 * - mono_metadata_str_hash () should be used for hashing strings.
1106 mono_method_get_imt_slot (MonoMethod *method)
1108 MONO_REQ_GC_NEUTRAL_MODE;
1110 MonoMethodSignature *sig;
1112 guint32 *hashes_start, *hashes;
1116 /* This can be used to stress tests the collision code */
1120 * We do this to simplify generic sharing. It will hurt
1121 * performance in cases where a class implements two different
1122 * instantiations of the same generic interface.
1123 * The code in build_imt_slots () depends on this.
1125 if (method->is_inflated)
1126 method = ((MonoMethodInflated*)method)->declaring;
1128 sig = mono_method_signature (method);
1129 hashes_count = sig->param_count + 4;
1130 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1131 hashes = hashes_start;
1133 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1134 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1135 method->klass->name_space, method->klass->name, method->name);
1138 /* Initialize hashes */
1139 hashes [0] = mono_metadata_str_hash (method->klass->name);
1140 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1141 hashes [2] = mono_metadata_str_hash (method->name);
1142 hashes [3] = mono_metadata_type_hash (sig->ret);
1143 for (i = 0; i < sig->param_count; i++) {
1144 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1147 /* Setup internal state */
1148 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1150 /* Handle most of the hashes */
1151 while (hashes_count > 3) {
1160 /* Handle the last 3 hashes (all the case statements fall through) */
1161 switch (hashes_count) {
1162 case 3 : c += hashes [2];
1163 case 2 : b += hashes [1];
1164 case 1 : a += hashes [0];
1166 case 0: /* nothing left to add */
1170 g_free (hashes_start);
1171 /* Report the result */
1172 return c % MONO_IMT_SIZE;
1181 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1182 MONO_REQ_GC_NEUTRAL_MODE;
1184 guint32 imt_slot = mono_method_get_imt_slot (method);
1185 MonoImtBuilderEntry *entry;
1187 if (slot_num >= 0 && imt_slot != slot_num) {
1188 /* we build just a single imt slot and this is not it */
1192 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1193 entry->key = method;
1194 entry->value.vtable_slot = vtable_slot;
1195 entry->next = imt_builder [imt_slot];
1196 if (imt_builder [imt_slot] != NULL) {
1197 entry->children = imt_builder [imt_slot]->children + 1;
1198 if (entry->children == 1) {
1199 mono_stats.imt_slots_with_collisions++;
1200 *imt_collisions_bitmap |= (1 << imt_slot);
1203 entry->children = 0;
1204 mono_stats.imt_used_slots++;
1206 imt_builder [imt_slot] = entry;
1209 char *method_name = mono_method_full_name (method, TRUE);
1210 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1211 method, method_name, imt_slot, vtable_slot, entry->children);
1212 g_free (method_name);
1219 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1221 MonoMethod *method = e->key;
1222 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1226 method->klass->name_space,
1227 method->klass->name,
1230 printf (" * %s: NULL\n", message);
1236 compare_imt_builder_entries (const void *p1, const void *p2) {
1237 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1238 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1240 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1244 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1246 MONO_REQ_GC_NEUTRAL_MODE;
1248 int count = end - start;
1249 int chunk_start = out_array->len;
1252 for (i = start; i < end; ++i) {
1253 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1254 item->key = sorted_array [i]->key;
1255 item->value = sorted_array [i]->value;
1256 item->has_target_code = sorted_array [i]->has_target_code;
1257 item->is_equals = TRUE;
1259 item->check_target_idx = out_array->len + 1;
1261 item->check_target_idx = 0;
1262 g_ptr_array_add (out_array, item);
1265 int middle = start + count / 2;
1266 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1268 item->key = sorted_array [middle]->key;
1269 item->is_equals = FALSE;
1270 g_ptr_array_add (out_array, item);
1271 imt_emit_ir (sorted_array, start, middle, out_array);
1272 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1278 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1279 MONO_REQ_GC_NEUTRAL_MODE;
1281 int number_of_entries = entries->children + 1;
1282 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1283 GPtrArray *result = g_ptr_array_new ();
1284 MonoImtBuilderEntry *current_entry;
1287 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1288 sorted_array [i] = current_entry;
1290 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1292 /*for (i = 0; i < number_of_entries; i++) {
1293 print_imt_entry (" sorted array:", sorted_array [i], i);
1296 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1298 g_free (sorted_array);
1303 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1305 MONO_REQ_GC_NEUTRAL_MODE;
1307 if (imt_builder_entry != NULL) {
1308 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1309 /* No collision, return the vtable slot contents */
1310 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1312 /* Collision, build the trampoline */
1313 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1316 result = imt_trampoline_builder (vtable, domain,
1317 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1318 for (i = 0; i < imt_ir->len; ++i)
1319 g_free (g_ptr_array_index (imt_ir, i));
1320 g_ptr_array_free (imt_ir, TRUE);
1332 static MonoImtBuilderEntry*
1333 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1336 * LOCKING: requires the loader and domain locks.
1340 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1342 MONO_REQ_GC_NEUTRAL_MODE;
1346 guint32 imt_collisions_bitmap = 0;
1347 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1348 int method_count = 0;
1349 gboolean record_method_count_for_max_collisions = FALSE;
1350 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1353 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1355 for (i = 0; i < klass->interface_offsets_count; ++i) {
1356 MonoClass *iface = klass->interfaces_packed [i];
1357 int interface_offset = klass->interface_offsets_packed [i];
1358 int method_slot_in_interface, vt_slot;
1360 if (mono_class_has_variant_generic_params (iface))
1361 has_variant_iface = TRUE;
1363 mono_class_setup_methods (iface);
1364 vt_slot = interface_offset;
1365 int mcount = mono_class_get_method_count (iface);
1366 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1369 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
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 (mono_class_get_generic_class (iface)->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 int mcount = mono_class_get_method_count (iface);
1402 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1403 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1405 if (method->is_generic)
1406 has_generic_virtual = TRUE;
1407 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1409 interface_offset += mcount;
1412 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1413 /* overwrite the imt slot only if we're building all the entries or if
1414 * we're building this specific one
1416 if (slot_num < 0 || i == slot_num) {
1417 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1420 if (imt_builder [i]) {
1421 MonoImtBuilderEntry *entry;
1423 /* Link entries with imt_builder [i] */
1424 for (entry = entries; entry->next; entry = entry->next) {
1426 MonoMethod *method = (MonoMethod*)entry->key;
1427 char *method_name = mono_method_full_name (method, TRUE);
1428 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1429 g_free (method_name);
1432 entry->next = imt_builder [i];
1433 entries->children += imt_builder [i]->children + 1;
1435 imt_builder [i] = entries;
1438 if (has_generic_virtual || has_variant_iface) {
1440 * There might be collisions later when the the trampoline is expanded.
1442 imt_collisions_bitmap |= (1 << i);
1445 * The IMT trampoline might be called with an instance of one of the
1446 * generic virtual methods, so has to fallback to the IMT trampoline.
1448 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1450 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1453 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1457 if (imt_builder [i] != NULL) {
1458 int methods_in_slot = imt_builder [i]->children + 1;
1459 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1460 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1461 record_method_count_for_max_collisions = TRUE;
1463 method_count += methods_in_slot;
1467 mono_stats.imt_number_of_methods += method_count;
1468 if (record_method_count_for_max_collisions) {
1469 mono_stats.imt_method_count_when_max_collisions = method_count;
1472 for (i = 0; i < MONO_IMT_SIZE; i++) {
1473 MonoImtBuilderEntry* entry = imt_builder [i];
1474 while (entry != NULL) {
1475 MonoImtBuilderEntry* next = entry->next;
1480 g_free (imt_builder);
1481 /* we OR the bitmap since we may build just a single imt slot at a time */
1482 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1486 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1487 MONO_REQ_GC_NEUTRAL_MODE;
1489 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1493 * mono_vtable_build_imt_slot:
1494 * @vtable: virtual object table struct
1495 * @imt_slot: slot in the IMT table
1497 * Fill the given @imt_slot in the IMT table of @vtable with
1498 * a trampoline or a trampoline for the case of collisions.
1499 * This is part of the internal mono API.
1501 * LOCKING: Take the domain lock.
1504 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1506 MONO_REQ_GC_NEUTRAL_MODE;
1508 gpointer *imt = (gpointer*)vtable;
1509 imt -= MONO_IMT_SIZE;
1510 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1512 /* no support for extra interfaces: the proxy objects will need
1513 * to build the complete IMT
1514 * Update and heck needs to ahppen inside the proper domain lock, as all
1515 * the changes made to a MonoVTable.
1517 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1518 mono_domain_lock (vtable->domain);
1519 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1520 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1521 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1522 mono_domain_unlock (vtable->domain);
1523 mono_loader_unlock ();
1526 #define THUNK_THRESHOLD 10
1529 * mono_method_alloc_generic_virtual_trampoline:
1531 * @size: size in bytes
1533 * Allocs size bytes to be used for the code of a generic virtual
1534 * trampoline. It's either allocated from the domain's code manager or
1535 * reused from a previously invalidated piece.
1537 * LOCKING: The domain lock must be held.
1540 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1542 MONO_REQ_GC_NEUTRAL_MODE;
1544 static gboolean inited = FALSE;
1545 static int generic_virtual_trampolines_size = 0;
1548 mono_counters_register ("Generic virtual trampoline bytes",
1549 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1552 generic_virtual_trampolines_size += size;
1554 return mono_domain_code_reserve (domain, size);
1557 typedef struct _GenericVirtualCase {
1561 struct _GenericVirtualCase *next;
1562 } GenericVirtualCase;
1565 * get_generic_virtual_entries:
1567 * Return IMT entries for the generic virtual method instances and
1568 * variant interface methods for vtable slot
1571 static MonoImtBuilderEntry*
1572 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1574 MONO_REQ_GC_NEUTRAL_MODE;
1576 GenericVirtualCase *list;
1577 MonoImtBuilderEntry *entries;
1579 mono_domain_lock (domain);
1580 if (!domain->generic_virtual_cases)
1581 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1583 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1586 for (; list; list = list->next) {
1587 MonoImtBuilderEntry *entry;
1589 if (list->count < THUNK_THRESHOLD)
1592 entry = g_new0 (MonoImtBuilderEntry, 1);
1593 entry->key = list->method;
1594 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1595 entry->has_target_code = 1;
1597 entry->children = entries->children + 1;
1598 entry->next = entries;
1602 mono_domain_unlock (domain);
1604 /* FIXME: Leaking memory ? */
1609 * mono_method_add_generic_virtual_invocation:
1611 * @vtable_slot: pointer to the vtable slot
1612 * @method: the inflated generic virtual method
1613 * @code: the method's code
1615 * Registers a call via unmanaged code to a generic virtual method
1616 * instantiation or variant interface method. If the number of calls reaches a threshold
1617 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1618 * virtual method trampoline.
1621 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1622 gpointer *vtable_slot,
1623 MonoMethod *method, gpointer code)
1625 MONO_REQ_GC_NEUTRAL_MODE;
1627 static gboolean inited = FALSE;
1628 static int num_added = 0;
1629 static int num_freed = 0;
1631 GenericVirtualCase *gvc, *list;
1632 MonoImtBuilderEntry *entries;
1636 mono_domain_lock (domain);
1637 if (!domain->generic_virtual_cases)
1638 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1641 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1642 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1646 /* Check whether the case was already added */
1647 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1650 if (gvc->method == method)
1655 /* If not found, make a new one */
1657 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1658 gvc->method = method;
1661 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1663 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1668 if (++gvc->count == THUNK_THRESHOLD) {
1669 gpointer *old_thunk = (void **)*vtable_slot;
1670 gpointer vtable_trampoline = NULL;
1671 gpointer imt_trampoline = NULL;
1673 if ((gpointer)vtable_slot < (gpointer)vtable) {
1674 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1675 int imt_slot = MONO_IMT_SIZE + displacement;
1677 /* Force the rebuild of the trampoline at the next call */
1678 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1679 *vtable_slot = imt_trampoline;
1681 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1683 entries = get_generic_virtual_entries (domain, vtable_slot);
1685 sorted = imt_sort_slot_entries (entries);
1687 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1691 MonoImtBuilderEntry *next = entries->next;
1696 for (i = 0; i < sorted->len; ++i)
1697 g_free (g_ptr_array_index (sorted, i));
1698 g_ptr_array_free (sorted, TRUE);
1700 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1705 mono_domain_unlock (domain);
1708 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1711 * mono_class_vtable:
1712 * @domain: the application domain
1713 * @class: the class to initialize
1715 * VTables are domain specific because we create domain specific code, and
1716 * they contain the domain specific static class data.
1717 * On failure, NULL is returned, and class->exception_type is set.
1720 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1723 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1724 mono_error_cleanup (&error);
1729 * mono_class_vtable_full:
1730 * @domain: the application domain
1731 * @class: the class to initialize
1732 * @error set on failure.
1734 * VTables are domain specific because we create domain specific code, and
1735 * they contain the domain specific static class data.
1738 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1740 MONO_REQ_GC_UNSAFE_MODE;
1742 MonoClassRuntimeInfo *runtime_info;
1744 mono_error_init (error);
1748 if (mono_class_has_failure (klass)) {
1749 mono_error_set_for_class_failure (error, klass);
1753 /* this check can be inlined in jitted code, too */
1754 runtime_info = klass->runtime_info;
1755 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1756 return runtime_info->domain_vtables [domain->domain_id];
1757 return mono_class_create_runtime_vtable (domain, klass, error);
1761 * mono_class_try_get_vtable:
1762 * @domain: the application domain
1763 * @class: the class to initialize
1765 * This function tries to get the associated vtable from @class if
1766 * it was already created.
1769 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1771 MONO_REQ_GC_NEUTRAL_MODE;
1773 MonoClassRuntimeInfo *runtime_info;
1777 runtime_info = klass->runtime_info;
1778 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1779 return runtime_info->domain_vtables [domain->domain_id];
1784 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1786 MONO_REQ_GC_NEUTRAL_MODE;
1788 size_t alloc_offset;
1791 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1792 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1793 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1795 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1796 g_assert ((imt_table_bytes & 7) == 4);
1803 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1807 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1809 MONO_REQ_GC_UNSAFE_MODE;
1812 MonoClassRuntimeInfo *runtime_info, *old_info;
1813 MonoClassField *field;
1815 int i, vtable_slots;
1816 size_t imt_table_bytes;
1818 guint32 vtable_size, class_size;
1820 gpointer *interface_offsets;
1822 mono_error_init (error);
1824 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1825 mono_domain_lock (domain);
1826 runtime_info = klass->runtime_info;
1827 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1828 mono_domain_unlock (domain);
1829 mono_loader_unlock ();
1830 return runtime_info->domain_vtables [domain->domain_id];
1832 if (!klass->inited || mono_class_has_failure (klass)) {
1833 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1834 mono_domain_unlock (domain);
1835 mono_loader_unlock ();
1836 mono_error_set_for_class_failure (error, klass);
1841 /* Array types require that their element type be valid*/
1842 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1843 MonoClass *element_class = klass->element_class;
1844 if (!element_class->inited)
1845 mono_class_init (element_class);
1847 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1848 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1849 mono_class_setup_vtable (element_class);
1851 if (mono_class_has_failure (element_class)) {
1852 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1853 if (!mono_class_has_failure (klass))
1854 mono_class_set_type_load_failure (klass, "");
1855 mono_domain_unlock (domain);
1856 mono_loader_unlock ();
1857 mono_error_set_for_class_failure (error, klass);
1863 * For some classes, mono_class_init () already computed klass->vtable_size, and
1864 * that is all that is needed because of the vtable trampolines.
1866 if (!klass->vtable_size)
1867 mono_class_setup_vtable (klass);
1869 if (mono_class_is_ginst (klass) && !klass->vtable)
1870 mono_class_check_vtable_constraints (klass, NULL);
1872 /* Initialize klass->has_finalize */
1873 mono_class_has_finalizer (klass);
1875 if (mono_class_has_failure (klass)) {
1876 mono_domain_unlock (domain);
1877 mono_loader_unlock ();
1878 mono_error_set_for_class_failure (error, klass);
1882 vtable_slots = klass->vtable_size;
1883 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1884 class_size = mono_class_data_size (klass);
1888 if (klass->interface_offsets_count) {
1889 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1890 mono_stats.imt_number_of_tables++;
1891 mono_stats.imt_tables_size += imt_table_bytes;
1893 imt_table_bytes = 0;
1896 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1898 mono_stats.used_class_count++;
1899 mono_stats.class_vtable_size += vtable_size;
1901 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1902 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1903 g_assert (!((gsize)vt & 7));
1906 vt->rank = klass->rank;
1907 vt->domain = domain;
1909 mono_class_compute_gc_descriptor (klass);
1911 * We can't use typed allocation in the non-root domains, since the
1912 * collector needs the GC descriptor stored in the vtable even after
1913 * the mempool containing the vtable is destroyed when the domain is
1914 * unloaded. An alternative might be to allocate vtables in the GC
1915 * heap, but this does not seem to work (it leads to crashes inside
1916 * libgc). If that approach is tried, two gc descriptors need to be
1917 * allocated for each class: one for the root domain, and one for all
1918 * other domains. The second descriptor should contain a bit for the
1919 * vtable field in MonoObject, since we can no longer assume the
1920 * vtable is reachable by other roots after the appdomain is unloaded.
1922 #ifdef HAVE_BOEHM_GC
1923 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1924 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1927 vt->gc_descr = klass->gc_descr;
1929 gc_bits = mono_gc_get_vtable_bits (klass);
1930 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1932 vt->gc_bits = gc_bits;
1935 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1936 if (klass->has_static_refs) {
1937 MonoGCDescriptor statics_gc_descr;
1939 gsize default_bitmap [4] = {0};
1942 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1943 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1944 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1945 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1946 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1947 if (bitmap != default_bitmap)
1950 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1952 vt->has_static_fields = TRUE;
1953 mono_stats.class_static_data_size += class_size;
1957 while ((field = mono_class_get_fields (klass, &iter))) {
1958 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1960 if (mono_field_is_deleted (field))
1962 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1963 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1964 if (special_static != SPECIAL_STATIC_NONE) {
1965 guint32 size, offset;
1967 gsize default_bitmap [4] = {0};
1972 if (mono_type_is_reference (field->type)) {
1973 default_bitmap [0] = 1;
1975 bitmap = default_bitmap;
1976 } else if (mono_type_is_struct (field->type)) {
1977 fclass = mono_class_from_mono_type (field->type);
1978 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1979 numbits = max_set + 1;
1981 default_bitmap [0] = 0;
1983 bitmap = default_bitmap;
1985 size = mono_type_size (field->type, &align);
1986 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1987 if (!domain->special_static_fields)
1988 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1989 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1990 if (bitmap != default_bitmap)
1993 * This marks the field as special static to speed up the
1994 * checks in mono_field_static_get/set_value ().
2000 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2001 MonoClass *fklass = mono_class_from_mono_type (field->type);
2002 const char *data = mono_field_get_data (field);
2004 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2005 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2006 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2009 if (fklass->valuetype) {
2010 memcpy (t, data, mono_class_value_size (fklass, NULL));
2012 /* it's a pointer type: add check */
2013 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2020 vt->max_interface_id = klass->max_interface_id;
2021 vt->interface_bitmap = klass->interface_bitmap;
2023 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2024 // class->name, klass->interface_offsets_count);
2026 /* Initialize vtable */
2027 if (callbacks.get_vtable_trampoline) {
2028 // This also covers the AOT case
2029 for (i = 0; i < klass->vtable_size; ++i) {
2030 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2033 mono_class_setup_vtable (klass);
2035 for (i = 0; i < klass->vtable_size; ++i) {
2038 cm = klass->vtable [i];
2040 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2041 if (!is_ok (error)) {
2042 mono_domain_unlock (domain);
2043 mono_loader_unlock ();
2050 if (imt_table_bytes) {
2051 /* Now that the vtable is full, we can actually fill up the IMT */
2052 for (i = 0; i < MONO_IMT_SIZE; ++i)
2053 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2057 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2058 * re-acquire them and check if another thread has created the vtable in the meantime.
2060 /* Special case System.MonoType to avoid infinite recursion */
2061 if (klass != mono_defaults.runtimetype_class) {
2062 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2063 if (!is_ok (error)) {
2064 mono_domain_unlock (domain);
2065 mono_loader_unlock ();
2069 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2070 /* This is unregistered in
2071 unregister_vtable_reflection_type() in
2073 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2076 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2078 /* class_vtable_array keeps an array of created vtables
2080 g_ptr_array_add (domain->class_vtable_array, vt);
2081 /* klass->runtime_info is protected by the loader lock, both when
2082 * it it enlarged and when it is stored info.
2086 * Store the vtable in klass->runtime_info.
2087 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2089 mono_memory_barrier ();
2091 old_info = klass->runtime_info;
2092 if (old_info && old_info->max_domain >= domain->domain_id) {
2093 /* someone already created a large enough runtime info */
2094 old_info->domain_vtables [domain->domain_id] = vt;
2096 int new_size = domain->domain_id;
2098 new_size = MAX (new_size, old_info->max_domain);
2100 /* make the new size a power of two */
2102 while (new_size > i)
2105 /* this is a bounded memory retention issue: may want to
2106 * handle it differently when we'll have a rcu-like system.
2108 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2109 runtime_info->max_domain = new_size - 1;
2110 /* copy the stuff from the older info */
2112 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2114 runtime_info->domain_vtables [domain->domain_id] = vt;
2116 mono_memory_barrier ();
2117 klass->runtime_info = runtime_info;
2120 if (klass == mono_defaults.runtimetype_class) {
2121 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2122 if (!is_ok (error)) {
2123 mono_domain_unlock (domain);
2124 mono_loader_unlock ();
2128 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2129 /* This is unregistered in
2130 unregister_vtable_reflection_type() in
2132 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2135 mono_domain_unlock (domain);
2136 mono_loader_unlock ();
2138 /* make sure the parent is initialized */
2139 /*FIXME shouldn't this fail the current type?*/
2141 mono_class_vtable_full (domain, klass->parent, error);
2146 #ifndef DISABLE_REMOTING
2148 * mono_class_proxy_vtable:
2149 * @domain: the application domain
2150 * @remove_class: the remote class
2151 * @error: set on error
2153 * Creates a vtable for transparent proxies. It is basically
2154 * a copy of the real vtable of the class wrapped in @remote_class,
2155 * but all function pointers invoke the remoting functions, and
2156 * vtable->klass points to the transparent proxy class, and not to @class.
2158 * On failure returns NULL and sets @error
2161 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2163 MONO_REQ_GC_UNSAFE_MODE;
2165 MonoVTable *vt, *pvt;
2166 int i, j, vtsize, extra_interface_vtsize = 0;
2167 guint32 max_interface_id;
2169 GSList *extra_interfaces = NULL;
2170 MonoClass *klass = remote_class->proxy_class;
2171 gpointer *interface_offsets;
2172 uint8_t *bitmap = NULL;
2174 size_t imt_table_bytes;
2176 #ifdef COMPRESSED_INTERFACE_BITMAP
2180 mono_error_init (error);
2182 vt = mono_class_vtable (domain, klass);
2183 g_assert (vt); /*FIXME property handle failure*/
2184 max_interface_id = vt->max_interface_id;
2186 /* Calculate vtable space for extra interfaces */
2187 for (j = 0; j < remote_class->interface_count; j++) {
2188 MonoClass* iclass = remote_class->interfaces[j];
2192 /*FIXME test for interfaces with variant generic arguments*/
2193 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2194 continue; /* interface implemented by the class */
2195 if (g_slist_find (extra_interfaces, iclass))
2198 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2200 method_count = mono_class_num_methods (iclass);
2202 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2206 for (i = 0; i < ifaces->len; ++i) {
2207 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2208 /*FIXME test for interfaces with variant generic arguments*/
2209 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2210 continue; /* interface implemented by the class */
2211 if (g_slist_find (extra_interfaces, ic))
2213 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2214 method_count += mono_class_num_methods (ic);
2216 g_ptr_array_free (ifaces, TRUE);
2220 extra_interface_vtsize += method_count * sizeof (gpointer);
2221 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2224 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2225 mono_stats.imt_number_of_tables++;
2226 mono_stats.imt_tables_size += imt_table_bytes;
2228 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2230 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2232 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2233 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2234 g_assert (!((gsize)pvt & 7));
2236 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2238 pvt->klass = mono_defaults.transparent_proxy_class;
2239 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2240 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2242 /* initialize vtable */
2243 mono_class_setup_vtable (klass);
2244 for (i = 0; i < klass->vtable_size; ++i) {
2247 if ((cm = klass->vtable [i])) {
2248 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2252 pvt->vtable [i] = NULL;
2255 if (mono_class_is_abstract (klass)) {
2256 /* create trampolines for abstract methods */
2257 for (k = klass; k; k = k->parent) {
2259 gpointer iter = NULL;
2260 while ((m = mono_class_get_methods (k, &iter)))
2261 if (!pvt->vtable [m->slot]) {
2262 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2269 pvt->max_interface_id = max_interface_id;
2270 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2271 #ifdef COMPRESSED_INTERFACE_BITMAP
2272 bitmap = (uint8_t *)g_malloc0 (bsize);
2274 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2277 for (i = 0; i < klass->interface_offsets_count; ++i) {
2278 int interface_id = klass->interfaces_packed [i]->interface_id;
2279 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2282 if (extra_interfaces) {
2283 int slot = klass->vtable_size;
2289 /* Create trampolines for the methods of the interfaces */
2290 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2291 interf = (MonoClass *)list_item->data;
2293 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2297 while ((cm = mono_class_get_methods (interf, &iter))) {
2298 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2303 slot += mono_class_num_methods (interf);
2307 /* Now that the vtable is full, we can actually fill up the IMT */
2308 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2309 if (extra_interfaces) {
2310 g_slist_free (extra_interfaces);
2313 #ifdef COMPRESSED_INTERFACE_BITMAP
2314 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2315 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2316 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2319 pvt->interface_bitmap = bitmap;
2323 if (extra_interfaces)
2324 g_slist_free (extra_interfaces);
2325 #ifdef COMPRESSED_INTERFACE_BITMAP
2331 #endif /* DISABLE_REMOTING */
2334 * mono_class_field_is_special_static:
2336 * Returns whether @field is a thread/context static field.
2339 mono_class_field_is_special_static (MonoClassField *field)
2341 MONO_REQ_GC_NEUTRAL_MODE
2343 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2345 if (mono_field_is_deleted (field))
2347 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2348 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2355 * mono_class_field_get_special_static_type:
2356 * @field: The MonoClassField describing the field.
2358 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2359 * SPECIAL_STATIC_NONE otherwise.
2362 mono_class_field_get_special_static_type (MonoClassField *field)
2364 MONO_REQ_GC_NEUTRAL_MODE
2366 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2367 return SPECIAL_STATIC_NONE;
2368 if (mono_field_is_deleted (field))
2369 return SPECIAL_STATIC_NONE;
2370 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2371 return field_is_special_static (field->parent, field);
2372 return SPECIAL_STATIC_NONE;
2376 * mono_class_has_special_static_fields:
2378 * Returns whenever @klass has any thread/context static fields.
2381 mono_class_has_special_static_fields (MonoClass *klass)
2383 MONO_REQ_GC_NEUTRAL_MODE
2385 MonoClassField *field;
2389 while ((field = mono_class_get_fields (klass, &iter))) {
2390 g_assert (field->parent == klass);
2391 if (mono_class_field_is_special_static (field))
2398 #ifndef DISABLE_REMOTING
2400 * create_remote_class_key:
2401 * Creates an array of pointers that can be used as a hash key for a remote class.
2402 * The first element of the array is the number of pointers.
2405 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2407 MONO_REQ_GC_NEUTRAL_MODE;
2412 if (remote_class == NULL) {
2413 if (mono_class_is_interface (extra_class)) {
2414 key = (void **)g_malloc (sizeof(gpointer) * 3);
2415 key [0] = GINT_TO_POINTER (2);
2416 key [1] = mono_defaults.marshalbyrefobject_class;
2417 key [2] = extra_class;
2419 key = (void **)g_malloc (sizeof(gpointer) * 2);
2420 key [0] = GINT_TO_POINTER (1);
2421 key [1] = extra_class;
2424 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2425 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2426 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2427 key [1] = remote_class->proxy_class;
2429 // Keep the list of interfaces sorted
2430 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2431 if (extra_class && remote_class->interfaces [i] > extra_class) {
2432 key [j++] = extra_class;
2435 key [j] = remote_class->interfaces [i];
2438 key [j] = extra_class;
2440 // Replace the old class. The interface list is the same
2441 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2442 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2443 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2444 for (i = 0; i < remote_class->interface_count; i++)
2445 key [2 + i] = remote_class->interfaces [i];
2453 * copy_remote_class_key:
2455 * Make a copy of KEY in the domain and return the copy.
2458 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2460 MONO_REQ_GC_NEUTRAL_MODE
2462 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2463 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2465 memcpy (mp_key, key, key_size);
2471 * mono_remote_class:
2472 * @domain: the application domain
2473 * @class_name: name of the remote class
2474 * @error: set on error
2476 * Creates and initializes a MonoRemoteClass object for a remote type.
2478 * On failure returns NULL and sets @error
2481 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2483 MONO_REQ_GC_UNSAFE_MODE;
2485 MonoRemoteClass *rc;
2486 gpointer* key, *mp_key;
2489 mono_error_init (error);
2491 key = create_remote_class_key (NULL, proxy_class);
2493 mono_domain_lock (domain);
2494 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2498 mono_domain_unlock (domain);
2502 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2503 if (!is_ok (error)) {
2505 mono_domain_unlock (domain);
2509 mp_key = copy_remote_class_key (domain, key);
2513 if (mono_class_is_interface (proxy_class)) {
2514 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2515 rc->interface_count = 1;
2516 rc->interfaces [0] = proxy_class;
2517 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2519 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2520 rc->interface_count = 0;
2521 rc->proxy_class = proxy_class;
2524 rc->default_vtable = NULL;
2525 rc->xdomain_vtable = NULL;
2526 rc->proxy_class_name = name;
2527 #ifndef DISABLE_PERFCOUNTERS
2528 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2531 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2533 mono_domain_unlock (domain);
2538 * clone_remote_class:
2539 * Creates a copy of the remote_class, adding the provided class or interface
2541 static MonoRemoteClass*
2542 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2544 MONO_REQ_GC_NEUTRAL_MODE;
2546 MonoRemoteClass *rc;
2547 gpointer* key, *mp_key;
2549 key = create_remote_class_key (remote_class, extra_class);
2550 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2556 mp_key = copy_remote_class_key (domain, key);
2560 if (mono_class_is_interface (extra_class)) {
2562 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2563 rc->proxy_class = remote_class->proxy_class;
2564 rc->interface_count = remote_class->interface_count + 1;
2566 // Keep the list of interfaces sorted, since the hash key of
2567 // the remote class depends on this
2568 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2569 if (remote_class->interfaces [i] > extra_class && i == j)
2570 rc->interfaces [j++] = extra_class;
2571 rc->interfaces [j] = remote_class->interfaces [i];
2574 rc->interfaces [j] = extra_class;
2576 // Replace the old class. The interface array is the same
2577 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2578 rc->proxy_class = extra_class;
2579 rc->interface_count = remote_class->interface_count;
2580 if (rc->interface_count > 0)
2581 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2584 rc->default_vtable = NULL;
2585 rc->xdomain_vtable = NULL;
2586 rc->proxy_class_name = remote_class->proxy_class_name;
2588 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2594 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2596 MONO_REQ_GC_UNSAFE_MODE;
2598 mono_error_init (error);
2600 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2601 mono_domain_lock (domain);
2602 if (rp->target_domain_id != -1) {
2603 if (remote_class->xdomain_vtable == NULL)
2604 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2605 mono_domain_unlock (domain);
2606 mono_loader_unlock ();
2607 return_val_if_nok (error, NULL);
2608 return remote_class->xdomain_vtable;
2610 if (remote_class->default_vtable == NULL) {
2613 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2614 klass = mono_class_from_mono_type (type);
2616 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)))
2617 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2620 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2621 /* N.B. both branches of the if modify error */
2622 if (!is_ok (error)) {
2623 mono_domain_unlock (domain);
2624 mono_loader_unlock ();
2629 mono_domain_unlock (domain);
2630 mono_loader_unlock ();
2631 return remote_class->default_vtable;
2635 * mono_upgrade_remote_class:
2636 * @domain: the application domain
2637 * @tproxy: the proxy whose remote class has to be upgraded.
2638 * @klass: class to which the remote class can be casted.
2639 * @error: set on error
2641 * Updates the vtable of the remote class by adding the necessary method slots
2642 * and interface offsets so it can be safely casted to klass. klass can be a
2643 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2646 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2648 MONO_REQ_GC_UNSAFE_MODE;
2650 MonoTransparentProxy *tproxy;
2651 MonoRemoteClass *remote_class;
2652 gboolean redo_vtable;
2654 mono_error_init (error);
2655 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2656 mono_domain_lock (domain);
2658 tproxy = (MonoTransparentProxy*) proxy_object;
2659 remote_class = tproxy->remote_class;
2661 if (mono_class_is_interface (klass)) {
2664 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2665 if (remote_class->interfaces [i] == klass)
2666 redo_vtable = FALSE;
2669 redo_vtable = (remote_class->proxy_class != klass);
2673 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2674 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2680 mono_domain_unlock (domain);
2681 mono_loader_unlock ();
2682 return is_ok (error);
2684 #endif /* DISABLE_REMOTING */
2688 * mono_object_get_virtual_method:
2689 * @obj: object to operate on.
2692 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2693 * the instance of a callvirt of method.
2696 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2698 MONO_REQ_GC_UNSAFE_MODE;
2701 MonoMethod **vtable;
2702 gboolean is_proxy = FALSE;
2703 MonoMethod *res = NULL;
2705 klass = mono_object_class (obj);
2706 #ifndef DISABLE_REMOTING
2707 if (klass == mono_defaults.transparent_proxy_class) {
2708 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2713 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2716 mono_class_setup_vtable (klass);
2717 vtable = klass->vtable;
2719 if (method->slot == -1) {
2720 /* method->slot might not be set for instances of generic methods */
2721 if (method->is_inflated) {
2722 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2723 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2726 g_assert_not_reached ();
2730 /* check method->slot is a valid index: perform isinstance? */
2731 if (method->slot != -1) {
2732 if (mono_class_is_interface (method->klass)) {
2734 gboolean variance_used = FALSE;
2735 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2736 g_assert (iface_offset > 0);
2737 res = vtable [iface_offset + method->slot];
2740 res = vtable [method->slot];
2744 #ifndef DISABLE_REMOTING
2746 /* It may be an interface, abstract class method or generic method */
2747 if (!res || mono_method_signature (res)->generic_param_count)
2750 /* generic methods demand invoke_with_check */
2751 if (mono_method_signature (res)->generic_param_count)
2752 res = mono_marshal_get_remoting_invoke_with_check (res);
2755 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2756 res = mono_cominterop_get_invoke (res);
2759 res = mono_marshal_get_remoting_invoke (res);
2764 if (method->is_inflated) {
2766 /* Have to inflate the result */
2767 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2768 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2778 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2780 MONO_REQ_GC_UNSAFE_MODE;
2782 MonoObject *result = NULL;
2784 g_assert (callbacks.runtime_invoke);
2786 mono_error_init (error);
2788 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2789 mono_profiler_method_start_invoke (method);
2791 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2793 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2794 mono_profiler_method_end_invoke (method);
2796 if (!mono_error_ok (error))
2803 * mono_runtime_invoke:
2804 * @method: method to invoke
2805 * @obJ: object instance
2806 * @params: arguments to the method
2807 * @exc: exception information.
2809 * Invokes the method represented by @method on the object @obj.
2811 * obj is the 'this' pointer, it should be NULL for static
2812 * methods, a MonoObject* for object instances and a pointer to
2813 * the value type for value types.
2815 * The params array contains the arguments to the method with the
2816 * same convention: MonoObject* pointers for object instances and
2817 * pointers to the value type otherwise.
2819 * From unmanaged code you'll usually use the
2820 * mono_runtime_invoke() variant.
2822 * Note that this function doesn't handle virtual methods for
2823 * you, it will exec the exact method you pass: we still need to
2824 * expose a function to lookup the derived class implementation
2825 * of a virtual method (there are examples of this in the code,
2828 * You can pass NULL as the exc argument if you don't want to
2829 * catch exceptions, otherwise, *exc will be set to the exception
2830 * thrown, if any. if an exception is thrown, you can't use the
2831 * MonoObject* result from the function.
2833 * If the method returns a value type, it is boxed in an object
2837 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2842 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2843 if (*exc == NULL && !mono_error_ok(&error)) {
2844 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2846 mono_error_cleanup (&error);
2848 res = mono_runtime_invoke_checked (method, obj, params, &error);
2849 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2855 * mono_runtime_try_invoke:
2856 * @method: method to invoke
2857 * @obJ: object instance
2858 * @params: arguments to the method
2859 * @exc: exception information.
2860 * @error: set on error
2862 * Invokes the method represented by @method on the object @obj.
2864 * obj is the 'this' pointer, it should be NULL for static
2865 * methods, a MonoObject* for object instances and a pointer to
2866 * the value type for value types.
2868 * The params array contains the arguments to the method with the
2869 * same convention: MonoObject* pointers for object instances and
2870 * pointers to the value type otherwise.
2872 * From unmanaged code you'll usually use the
2873 * mono_runtime_invoke() variant.
2875 * Note that this function doesn't handle virtual methods for
2876 * you, it will exec the exact method you pass: we still need to
2877 * expose a function to lookup the derived class implementation
2878 * of a virtual method (there are examples of this in the code,
2881 * For this function, you must not pass NULL as the exc argument if
2882 * you don't want to catch exceptions, use
2883 * mono_runtime_invoke_checked(). If an exception is thrown, you
2884 * can't use the MonoObject* result from the function.
2886 * If this method cannot be invoked, @error will be set and @exc and
2887 * the return value must not be used.
2889 * If the method returns a value type, it is boxed in an object
2893 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2895 MONO_REQ_GC_UNSAFE_MODE;
2897 g_assert (exc != NULL);
2899 if (mono_runtime_get_no_exec ())
2900 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2902 return do_runtime_invoke (method, obj, params, exc, error);
2906 * mono_runtime_invoke_checked:
2907 * @method: method to invoke
2908 * @obJ: object instance
2909 * @params: arguments to the method
2910 * @error: set on error
2912 * Invokes the method represented by @method on the object @obj.
2914 * obj is the 'this' pointer, it should be NULL for static
2915 * methods, a MonoObject* for object instances and a pointer to
2916 * the value type for value types.
2918 * The params array contains the arguments to the method with the
2919 * same convention: MonoObject* pointers for object instances and
2920 * pointers to the value type otherwise.
2922 * From unmanaged code you'll usually use the
2923 * mono_runtime_invoke() variant.
2925 * Note that this function doesn't handle virtual methods for
2926 * you, it will exec the exact method you pass: we still need to
2927 * expose a function to lookup the derived class implementation
2928 * of a virtual method (there are examples of this in the code,
2931 * If an exception is thrown, you can't use the MonoObject* result
2932 * from the function.
2934 * If this method cannot be invoked, @error will be set. If the
2935 * method throws an exception (and we're in coop mode) the exception
2936 * will be set in @error.
2938 * If the method returns a value type, it is boxed in an object
2942 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2944 MONO_REQ_GC_UNSAFE_MODE;
2946 if (mono_runtime_get_no_exec ())
2947 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2949 return do_runtime_invoke (method, obj, params, NULL, error);
2953 * mono_method_get_unmanaged_thunk:
2954 * @method: method to generate a thunk for.
2956 * Returns an unmanaged->managed thunk that can be used to call
2957 * a managed method directly from C.
2959 * The thunk's C signature closely matches the managed signature:
2961 * C#: public bool Equals (object obj);
2962 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2963 * MonoObject*, MonoException**);
2965 * The 1st ("this") parameter must not be used with static methods:
2967 * C#: public static bool ReferenceEquals (object a, object b);
2968 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2971 * The last argument must be a non-null pointer of a MonoException* pointer.
2972 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2973 * exception has been thrown in managed code. Otherwise it will point
2974 * to the MonoException* caught by the thunk. In this case, the result of
2975 * the thunk is undefined:
2977 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2978 * MonoException *ex = NULL;
2979 * Equals func = mono_method_get_unmanaged_thunk (method);
2980 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2982 * // handle exception
2985 * The calling convention of the thunk matches the platform's default
2986 * convention. This means that under Windows, C declarations must
2987 * contain the __stdcall attribute:
2989 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2990 * MonoObject*, MonoException**);
2994 * Value type arguments and return values are treated as they were objects:
2996 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2997 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2999 * Arguments must be properly boxed upon trunk's invocation, while return
3000 * values must be unboxed.
3003 mono_method_get_unmanaged_thunk (MonoMethod *method)
3005 MONO_REQ_GC_NEUTRAL_MODE;
3006 MONO_REQ_API_ENTRYPOINT;
3011 g_assert (!mono_threads_is_coop_enabled ());
3013 MONO_ENTER_GC_UNSAFE;
3014 method = mono_marshal_get_thunk_invoke_wrapper (method);
3015 res = mono_compile_method_checked (method, &error);
3016 mono_error_cleanup (&error);
3017 MONO_EXIT_GC_UNSAFE;
3023 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3025 MONO_REQ_GC_UNSAFE_MODE;
3029 /* object fields cannot be byref, so we don't need a
3031 gpointer *p = (gpointer*)dest;
3038 case MONO_TYPE_BOOLEAN:
3040 case MONO_TYPE_U1: {
3041 guint8 *p = (guint8*)dest;
3042 *p = value ? *(guint8*)value : 0;
3047 case MONO_TYPE_CHAR: {
3048 guint16 *p = (guint16*)dest;
3049 *p = value ? *(guint16*)value : 0;
3052 #if SIZEOF_VOID_P == 4
3057 case MONO_TYPE_U4: {
3058 gint32 *p = (gint32*)dest;
3059 *p = value ? *(gint32*)value : 0;
3062 #if SIZEOF_VOID_P == 8
3067 case MONO_TYPE_U8: {
3068 gint64 *p = (gint64*)dest;
3069 *p = value ? *(gint64*)value : 0;
3072 case MONO_TYPE_R4: {
3073 float *p = (float*)dest;
3074 *p = value ? *(float*)value : 0;
3077 case MONO_TYPE_R8: {
3078 double *p = (double*)dest;
3079 *p = value ? *(double*)value : 0;
3082 case MONO_TYPE_STRING:
3083 case MONO_TYPE_SZARRAY:
3084 case MONO_TYPE_CLASS:
3085 case MONO_TYPE_OBJECT:
3086 case MONO_TYPE_ARRAY:
3087 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3089 case MONO_TYPE_FNPTR:
3090 case MONO_TYPE_PTR: {
3091 gpointer *p = (gpointer*)dest;
3092 *p = deref_pointer? *(gpointer*)value: value;
3095 case MONO_TYPE_VALUETYPE:
3096 /* note that 't' and 'type->type' can be different */
3097 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3098 t = mono_class_enum_basetype (type->data.klass)->type;
3101 MonoClass *klass = mono_class_from_mono_type (type);
3102 int size = mono_class_value_size (klass, NULL);
3104 mono_gc_bzero_atomic (dest, size);
3106 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3109 case MONO_TYPE_GENERICINST:
3110 t = type->data.generic_class->container_class->byval_arg.type;
3113 g_error ("got type %x", type->type);
3118 * mono_field_set_value:
3119 * @obj: Instance object
3120 * @field: MonoClassField describing the field to set
3121 * @value: The value to be set
3123 * Sets the value of the field described by @field in the object instance @obj
3124 * to the value passed in @value. This method should only be used for instance
3125 * fields. For static fields, use mono_field_static_set_value.
3127 * The value must be on the native format of the field type.
3130 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3132 MONO_REQ_GC_UNSAFE_MODE;
3136 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3138 dest = (char*)obj + field->offset;
3139 mono_copy_value (field->type, dest, value, FALSE);
3143 * mono_field_static_set_value:
3144 * @field: MonoClassField describing the field to set
3145 * @value: The value to be set
3147 * Sets the value of the static field described by @field
3148 * to the value passed in @value.
3150 * The value must be on the native format of the field type.
3153 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3155 MONO_REQ_GC_UNSAFE_MODE;
3159 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3160 /* you cant set a constant! */
3161 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3163 if (field->offset == -1) {
3164 /* Special static */
3167 mono_domain_lock (vt->domain);
3168 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3169 mono_domain_unlock (vt->domain);
3170 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3172 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3174 mono_copy_value (field->type, dest, value, FALSE);
3178 * mono_vtable_get_static_field_data:
3180 * Internal use function: return a pointer to the memory holding the static fields
3181 * for a class or NULL if there are no static fields.
3182 * This is exported only for use by the debugger.
3185 mono_vtable_get_static_field_data (MonoVTable *vt)
3187 MONO_REQ_GC_NEUTRAL_MODE
3189 if (!vt->has_static_fields)
3191 return vt->vtable [vt->klass->vtable_size];
3195 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3197 MONO_REQ_GC_UNSAFE_MODE;
3201 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3202 if (field->offset == -1) {
3203 /* Special static */
3206 mono_domain_lock (vt->domain);
3207 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3208 mono_domain_unlock (vt->domain);
3209 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3211 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3214 src = (guint8*)obj + field->offset;
3221 * mono_field_get_value:
3222 * @obj: Object instance
3223 * @field: MonoClassField describing the field to fetch information from
3224 * @value: pointer to the location where the value will be stored
3226 * Use this routine to get the value of the field @field in the object
3229 * The pointer provided by value must be of the field type, for reference
3230 * types this is a MonoObject*, for value types its the actual pointer to
3235 * mono_field_get_value (obj, int_field, &i);
3238 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3240 MONO_REQ_GC_UNSAFE_MODE;
3246 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3248 src = (char*)obj + field->offset;
3249 mono_copy_value (field->type, value, src, TRUE);
3253 * mono_field_get_value_object:
3254 * @domain: domain where the object will be created (if boxing)
3255 * @field: MonoClassField describing the field to fetch information from
3256 * @obj: The object instance for the field.
3258 * Returns: a new MonoObject with the value from the given field. If the
3259 * field represents a value type, the value is boxed.
3263 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3266 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3267 mono_error_assert_ok (&error);
3272 * mono_field_get_value_object_checked:
3273 * @domain: domain where the object will be created (if boxing)
3274 * @field: MonoClassField describing the field to fetch information from
3275 * @obj: The object instance for the field.
3276 * @error: Set on error.
3278 * Returns: a new MonoObject with the value from the given field. If the
3279 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3283 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3285 MONO_REQ_GC_UNSAFE_MODE;
3287 mono_error_init (error);
3291 MonoVTable *vtable = NULL;
3293 gboolean is_static = FALSE;
3294 gboolean is_ref = FALSE;
3295 gboolean is_literal = FALSE;
3296 gboolean is_ptr = FALSE;
3297 MonoType *type = mono_field_get_type_checked (field, error);
3299 return_val_if_nok (error, NULL);
3301 switch (type->type) {
3302 case MONO_TYPE_STRING:
3303 case MONO_TYPE_OBJECT:
3304 case MONO_TYPE_CLASS:
3305 case MONO_TYPE_ARRAY:
3306 case MONO_TYPE_SZARRAY:
3311 case MONO_TYPE_BOOLEAN:
3314 case MONO_TYPE_CHAR:
3323 case MONO_TYPE_VALUETYPE:
3324 is_ref = type->byref;
3326 case MONO_TYPE_GENERICINST:
3327 is_ref = !mono_type_generic_inst_is_valuetype (type);
3333 g_error ("type 0x%x not handled in "
3334 "mono_field_get_value_object", type->type);
3338 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3341 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3345 vtable = mono_class_vtable_full (domain, field->parent, error);
3346 return_val_if_nok (error, NULL);
3348 if (!vtable->initialized) {
3349 mono_runtime_class_init_full (vtable, error);
3350 return_val_if_nok (error, NULL);
3359 get_default_field_value (domain, field, &o, error);
3360 return_val_if_nok (error, NULL);
3361 } else if (is_static) {
3362 mono_field_static_get_value_checked (vtable, field, &o, error);
3363 return_val_if_nok (error, NULL);
3365 mono_field_get_value (obj, field, &o);
3371 static MonoMethod *m;
3377 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3378 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3384 get_default_field_value (domain, field, v, error);
3385 return_val_if_nok (error, NULL);
3386 } else if (is_static) {
3387 mono_field_static_get_value_checked (vtable, field, v, error);
3388 return_val_if_nok (error, NULL);
3390 mono_field_get_value (obj, field, v);
3393 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3394 args [0] = ptr ? *ptr : NULL;
3395 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3396 return_val_if_nok (error, NULL);
3398 o = mono_runtime_invoke_checked (m, NULL, args, error);
3399 return_val_if_nok (error, NULL);
3404 /* boxed value type */
3405 klass = mono_class_from_mono_type (type);
3407 if (mono_class_is_nullable (klass))
3408 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3410 o = mono_object_new_checked (domain, klass, error);
3411 return_val_if_nok (error, NULL);
3412 v = ((gchar *) o) + sizeof (MonoObject);
3415 get_default_field_value (domain, field, v, error);
3416 return_val_if_nok (error, NULL);
3417 } else if (is_static) {
3418 mono_field_static_get_value_checked (vtable, field, v, error);
3419 return_val_if_nok (error, NULL);
3421 mono_field_get_value (obj, field, v);
3428 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3430 MONO_REQ_GC_UNSAFE_MODE;
3432 mono_error_init (error);
3434 const char *p = blob;
3435 mono_metadata_decode_blob_size (p, &p);
3438 case MONO_TYPE_BOOLEAN:
3441 *(guint8 *) value = *p;
3443 case MONO_TYPE_CHAR:
3446 *(guint16*) value = read16 (p);
3450 *(guint32*) value = read32 (p);
3454 *(guint64*) value = read64 (p);
3457 readr4 (p, (float*) value);
3460 readr8 (p, (double*) value);
3462 case MONO_TYPE_STRING:
3463 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3465 case MONO_TYPE_CLASS:
3466 *(gpointer*) value = NULL;
3470 g_warning ("type 0x%02x should not be in constant table", type);
3476 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3478 MONO_REQ_GC_NEUTRAL_MODE;
3480 MonoTypeEnum def_type;
3483 mono_error_init (error);
3485 data = mono_class_get_field_default_value (field, &def_type);
3486 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3490 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3492 MONO_REQ_GC_UNSAFE_MODE;
3496 mono_error_init (error);
3498 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3500 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3501 get_default_field_value (vt->domain, field, value, error);
3505 if (field->offset == -1) {
3506 /* Special static */
3507 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3508 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3510 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3512 mono_copy_value (field->type, value, src, TRUE);
3516 * mono_field_static_get_value:
3517 * @vt: vtable to the object
3518 * @field: MonoClassField describing the field to fetch information from
3519 * @value: where the value is returned
3521 * Use this routine to get the value of the static field @field value.
3523 * The pointer provided by value must be of the field type, for reference
3524 * types this is a MonoObject*, for value types its the actual pointer to
3529 * mono_field_static_get_value (vt, int_field, &i);
3532 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3534 MONO_REQ_GC_NEUTRAL_MODE;
3537 mono_field_static_get_value_checked (vt, field, value, &error);
3538 mono_error_cleanup (&error);
3542 * mono_field_static_get_value_checked:
3543 * @vt: vtable to the object
3544 * @field: MonoClassField describing the field to fetch information from
3545 * @value: where the value is returned
3546 * @error: set on error
3548 * Use this routine to get the value of the static field @field value.
3550 * The pointer provided by value must be of the field type, for reference
3551 * types this is a MonoObject*, for value types its the actual pointer to
3556 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3557 * if (!is_ok (error)) { ... }
3559 * On failure sets @error.
3562 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3564 MONO_REQ_GC_NEUTRAL_MODE;
3566 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3570 * mono_property_set_value:
3571 * @prop: MonoProperty to set
3572 * @obj: instance object on which to act
3573 * @params: parameters to pass to the propery
3574 * @exc: optional exception
3576 * Invokes the property's set method with the given arguments on the
3577 * object instance obj (or NULL for static properties).
3579 * You can pass NULL as the exc argument if you don't want to
3580 * catch exceptions, otherwise, *exc will be set to the exception
3581 * thrown, if any. if an exception is thrown, you can't use the
3582 * MonoObject* result from the function.
3585 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3587 MONO_REQ_GC_UNSAFE_MODE;
3590 do_runtime_invoke (prop->set, obj, params, exc, &error);
3591 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3592 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3594 mono_error_cleanup (&error);
3599 * mono_property_set_value_checked:
3600 * @prop: MonoProperty to set
3601 * @obj: instance object on which to act
3602 * @params: parameters to pass to the propery
3603 * @error: set on error
3605 * Invokes the property's set method with the given arguments on the
3606 * object instance obj (or NULL for static properties).
3608 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3609 * If an exception is thrown, it will be caught and returned via @error.
3612 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3614 MONO_REQ_GC_UNSAFE_MODE;
3618 mono_error_init (error);
3619 do_runtime_invoke (prop->set, obj, params, &exc, error);
3620 if (exc != NULL && is_ok (error))
3621 mono_error_set_exception_instance (error, (MonoException*)exc);
3622 return is_ok (error);
3626 * mono_property_get_value:
3627 * @prop: MonoProperty to fetch
3628 * @obj: instance object on which to act
3629 * @params: parameters to pass to the propery
3630 * @exc: optional exception
3632 * Invokes the property's get method with the given arguments on the
3633 * object instance obj (or NULL for static properties).
3635 * You can pass NULL as the exc argument if you don't want to
3636 * catch exceptions, otherwise, *exc will be set to the exception
3637 * thrown, if any. if an exception is thrown, you can't use the
3638 * MonoObject* result from the function.
3640 * Returns: the value from invoking the get method on the property.
3643 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3645 MONO_REQ_GC_UNSAFE_MODE;
3648 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3649 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3650 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3652 mono_error_cleanup (&error); /* FIXME don't raise here */
3659 * mono_property_get_value_checked:
3660 * @prop: MonoProperty to fetch
3661 * @obj: instance object on which to act
3662 * @params: parameters to pass to the propery
3663 * @error: set on error
3665 * Invokes the property's get method with the given arguments on the
3666 * object instance obj (or NULL for static properties).
3668 * If an exception is thrown, you can't use the
3669 * MonoObject* result from the function. The exception will be propagated via @error.
3671 * Returns: the value from invoking the get method on the property. On
3672 * failure returns NULL and sets @error.
3675 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3677 MONO_REQ_GC_UNSAFE_MODE;
3680 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3681 if (exc != NULL && !is_ok (error))
3682 mono_error_set_exception_instance (error, (MonoException*) exc);
3690 * mono_nullable_init:
3691 * @buf: The nullable structure to initialize.
3692 * @value: the value to initialize from
3693 * @klass: the type for the object
3695 * Initialize the nullable structure pointed to by @buf from @value which
3696 * should be a boxed value type. The size of @buf should be able to hold
3697 * as much data as the @klass->instance_size (which is the number of bytes
3698 * that will be copies).
3700 * Since Nullables have variable structure, we can not define a C
3701 * structure for them.
3704 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3706 MONO_REQ_GC_UNSAFE_MODE;
3708 MonoClass *param_class = klass->cast_class;
3710 mono_class_setup_fields (klass);
3711 g_assert (klass->fields_inited);
3713 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3714 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3716 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3718 if (param_class->has_references)
3719 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3721 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3723 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3728 * mono_nullable_box:
3729 * @buf: The buffer representing the data to be boxed
3730 * @klass: the type to box it as.
3731 * @error: set on oerr
3733 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3734 * @buf. On failure returns NULL and sets @error
3737 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3739 MONO_REQ_GC_UNSAFE_MODE;
3741 mono_error_init (error);
3742 MonoClass *param_class = klass->cast_class;
3744 mono_class_setup_fields (klass);
3745 g_assert (klass->fields_inited);
3747 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3748 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3750 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3751 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3752 return_val_if_nok (error, NULL);
3753 if (param_class->has_references)
3754 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3756 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3764 * mono_get_delegate_invoke:
3765 * @klass: The delegate class
3767 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3770 mono_get_delegate_invoke (MonoClass *klass)
3772 MONO_REQ_GC_NEUTRAL_MODE;
3776 /* This is called at runtime, so avoid the slower search in metadata */
3777 mono_class_setup_methods (klass);
3778 if (mono_class_has_failure (klass))
3780 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3785 * mono_get_delegate_begin_invoke:
3786 * @klass: The delegate class
3788 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3791 mono_get_delegate_begin_invoke (MonoClass *klass)
3793 MONO_REQ_GC_NEUTRAL_MODE;
3797 /* This is called at runtime, so avoid the slower search in metadata */
3798 mono_class_setup_methods (klass);
3799 if (mono_class_has_failure (klass))
3801 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3806 * mono_get_delegate_end_invoke:
3807 * @klass: The delegate class
3809 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3812 mono_get_delegate_end_invoke (MonoClass *klass)
3814 MONO_REQ_GC_NEUTRAL_MODE;
3818 /* This is called at runtime, so avoid the slower search in metadata */
3819 mono_class_setup_methods (klass);
3820 if (mono_class_has_failure (klass))
3822 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3827 * mono_runtime_delegate_invoke:
3828 * @delegate: pointer to a delegate object.
3829 * @params: parameters for the delegate.
3830 * @exc: Pointer to the exception result.
3832 * Invokes the delegate method @delegate with the parameters provided.
3834 * You can pass NULL as the exc argument if you don't want to
3835 * catch exceptions, otherwise, *exc will be set to the exception
3836 * thrown, if any. if an exception is thrown, you can't use the
3837 * MonoObject* result from the function.
3840 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3842 MONO_REQ_GC_UNSAFE_MODE;
3846 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3848 mono_error_cleanup (&error);
3851 if (!is_ok (&error))
3852 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3856 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3857 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3863 * mono_runtime_delegate_try_invoke:
3864 * @delegate: pointer to a delegate object.
3865 * @params: parameters for the delegate.
3866 * @exc: Pointer to the exception result.
3867 * @error: set on error
3869 * Invokes the delegate method @delegate with the parameters provided.
3871 * You can pass NULL as the exc argument if you don't want to
3872 * catch exceptions, otherwise, *exc will be set to the exception
3873 * thrown, if any. On failure to execute, @error will be set.
3874 * if an exception is thrown, you can't use the
3875 * MonoObject* result from the function.
3878 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3880 MONO_REQ_GC_UNSAFE_MODE;
3882 mono_error_init (error);
3884 MonoClass *klass = delegate->vtable->klass;
3887 im = mono_get_delegate_invoke (klass);
3889 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3892 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3894 o = mono_runtime_invoke_checked (im, delegate, params, error);
3901 * mono_runtime_delegate_invoke_checked:
3902 * @delegate: pointer to a delegate object.
3903 * @params: parameters for the delegate.
3904 * @error: set on error
3906 * Invokes the delegate method @delegate with the parameters provided.
3908 * On failure @error will be set and you can't use the MonoObject*
3909 * result from the function.
3912 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3914 mono_error_init (error);
3915 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3918 static char **main_args = NULL;
3919 static int num_main_args = 0;
3922 * mono_runtime_get_main_args:
3924 * Returns: a MonoArray with the arguments passed to the main program
3927 mono_runtime_get_main_args (void)
3929 MONO_REQ_GC_UNSAFE_MODE;
3931 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3932 mono_error_assert_ok (&error);
3937 * mono_runtime_get_main_args:
3938 * @error: set on error
3940 * Returns: a MonoArray with the arguments passed to the main
3941 * program. On failure returns NULL and sets @error.
3944 mono_runtime_get_main_args_checked (MonoError *error)
3948 MonoDomain *domain = mono_domain_get ();
3950 mono_error_init (error);
3952 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3953 return_val_if_nok (error, NULL);
3955 for (i = 0; i < num_main_args; ++i)
3956 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3962 free_main_args (void)
3964 MONO_REQ_GC_NEUTRAL_MODE;
3968 for (i = 0; i < num_main_args; ++i)
3969 g_free (main_args [i]);
3976 * mono_runtime_set_main_args:
3977 * @argc: number of arguments from the command line
3978 * @argv: array of strings from the command line
3980 * Set the command line arguments from an embedding application that doesn't otherwise call
3981 * mono_runtime_run_main ().
3984 mono_runtime_set_main_args (int argc, char* argv[])
3986 MONO_REQ_GC_NEUTRAL_MODE;
3991 main_args = g_new0 (char*, argc);
3992 num_main_args = argc;
3994 for (i = 0; i < argc; ++i) {
3997 utf8_arg = mono_utf8_from_external (argv[i]);
3998 if (utf8_arg == NULL) {
3999 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4000 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4004 main_args [i] = utf8_arg;
4011 * Prepare an array of arguments in order to execute a standard Main()
4012 * method (argc/argv contains the executable name). This method also
4013 * sets the command line argument value needed by System.Environment.
4017 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4019 MONO_REQ_GC_UNSAFE_MODE;
4023 MonoArray *args = NULL;
4024 MonoDomain *domain = mono_domain_get ();
4025 gchar *utf8_fullpath;
4026 MonoMethodSignature *sig;
4028 g_assert (method != NULL);
4030 mono_thread_set_main (mono_thread_current ());
4032 main_args = g_new0 (char*, argc);
4033 num_main_args = argc;
4035 if (!g_path_is_absolute (argv [0])) {
4036 gchar *basename = g_path_get_basename (argv [0]);
4037 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4041 utf8_fullpath = mono_utf8_from_external (fullpath);
4042 if(utf8_fullpath == NULL) {
4043 /* Printing the arg text will cause glib to
4044 * whinge about "Invalid UTF-8", but at least
4045 * its relevant, and shows the problem text
4048 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4049 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4056 utf8_fullpath = mono_utf8_from_external (argv[0]);
4057 if(utf8_fullpath == NULL) {
4058 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4059 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4064 main_args [0] = utf8_fullpath;
4066 for (i = 1; i < argc; ++i) {
4069 utf8_arg=mono_utf8_from_external (argv[i]);
4070 if(utf8_arg==NULL) {
4071 /* Ditto the comment about Invalid UTF-8 here */
4072 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4073 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4077 main_args [i] = utf8_arg;
4082 sig = mono_method_signature (method);
4084 g_print ("Unable to load Main method.\n");
4088 if (sig->param_count) {
4089 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4090 mono_error_assert_ok (&error);
4091 for (i = 0; i < argc; ++i) {
4092 /* The encodings should all work, given that
4093 * we've checked all these args for the
4096 gchar *str = mono_utf8_from_external (argv [i]);
4097 MonoString *arg = mono_string_new (domain, str);
4098 mono_array_setref (args, i, arg);
4102 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4103 mono_error_assert_ok (&error);
4106 mono_assembly_set_main (method->klass->image->assembly);
4112 * mono_runtime_run_main:
4113 * @method: the method to start the application with (usually Main)
4114 * @argc: number of arguments from the command line
4115 * @argv: array of strings from the command line
4116 * @exc: excetption results
4118 * Execute a standard Main() method (argc/argv contains the
4119 * executable name). This method also sets the command line argument value
4120 * needed by System.Environment.
4125 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4128 MONO_REQ_GC_UNSAFE_MODE;
4131 MonoArray *args = prepare_run_main (method, argc, argv);
4134 res = mono_runtime_try_exec_main (method, args, exc);
4136 res = mono_runtime_exec_main_checked (method, args, &error);
4137 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4143 * mono_runtime_run_main_checked:
4144 * @method: the method to start the application with (usually Main)
4145 * @argc: number of arguments from the command line
4146 * @argv: array of strings from the command line
4147 * @error: set on error
4149 * Execute a standard Main() method (argc/argv contains the
4150 * executable name). This method also sets the command line argument value
4151 * needed by System.Environment. On failure sets @error.
4156 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4159 mono_error_init (error);
4160 MonoArray *args = prepare_run_main (method, argc, argv);
4161 return mono_runtime_exec_main_checked (method, args, error);
4165 * mono_runtime_try_run_main:
4166 * @method: the method to start the application with (usually Main)
4167 * @argc: number of arguments from the command line
4168 * @argv: array of strings from the command line
4169 * @exc: set if Main throws an exception
4170 * @error: set if Main can't be executed
4172 * Execute a standard Main() method (argc/argv contains the executable
4173 * name). This method also sets the command line argument value needed
4174 * by System.Environment. On failure sets @error if Main can't be
4175 * executed or @exc if it threw and exception.
4180 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4184 MonoArray *args = prepare_run_main (method, argc, argv);
4185 return mono_runtime_try_exec_main (method, args, exc);
4190 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4192 static MonoMethod *serialize_method;
4198 if (!serialize_method) {
4199 MonoClass *klass = mono_class_get_remoting_services_class ();
4200 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4203 if (!serialize_method) {
4208 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4213 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4214 if (*exc == NULL && !mono_error_ok (&error))
4215 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4217 mono_error_cleanup (&error);
4226 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4228 MONO_REQ_GC_UNSAFE_MODE;
4230 static MonoMethod *deserialize_method;
4236 if (!deserialize_method) {
4237 MonoClass *klass = mono_class_get_remoting_services_class ();
4238 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4240 if (!deserialize_method) {
4248 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4249 if (*exc == NULL && !mono_error_ok (&error))
4250 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4252 mono_error_cleanup (&error);
4260 #ifndef DISABLE_REMOTING
4262 make_transparent_proxy (MonoObject *obj, MonoError *error)
4264 MONO_REQ_GC_UNSAFE_MODE;
4266 static MonoMethod *get_proxy_method;
4268 MonoDomain *domain = mono_domain_get ();
4269 MonoRealProxy *real_proxy;
4270 MonoReflectionType *reflection_type;
4271 MonoTransparentProxy *transparent_proxy;
4273 mono_error_init (error);
4275 if (!get_proxy_method)
4276 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4278 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4280 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4281 return_val_if_nok (error, NULL);
4282 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4283 return_val_if_nok (error, NULL);
4285 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4286 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4288 MonoObject *exc = NULL;
4290 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4291 if (exc != NULL && is_ok (error))
4292 mono_error_set_exception_instance (error, (MonoException*)exc);
4294 return (MonoObject*) transparent_proxy;
4296 #endif /* DISABLE_REMOTING */
4299 * mono_object_xdomain_representation
4301 * @target_domain: a domain
4302 * @error: set on error.
4304 * Creates a representation of obj in the domain target_domain. This
4305 * is either a copy of obj arrived through via serialization and
4306 * deserialization or a proxy, depending on whether the object is
4307 * serializable or marshal by ref. obj must not be in target_domain.
4309 * If the object cannot be represented in target_domain, NULL is
4310 * returned and @error is set appropriately.
4313 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4315 MONO_REQ_GC_UNSAFE_MODE;
4317 mono_error_init (error);
4318 MonoObject *deserialized = NULL;
4320 #ifndef DISABLE_REMOTING
4321 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4322 deserialized = make_transparent_proxy (obj, error);
4327 gboolean failure = FALSE;
4328 MonoDomain *domain = mono_domain_get ();
4329 MonoObject *serialized;
4330 MonoObject *exc = NULL;
4332 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4333 serialized = serialize_object (obj, &failure, &exc);
4334 mono_domain_set_internal_with_options (target_domain, FALSE);
4336 deserialized = deserialize_object (serialized, &failure, &exc);
4337 if (domain != target_domain)
4338 mono_domain_set_internal_with_options (domain, FALSE);
4340 mono_error_set_exception_instance (error, (MonoException*)exc);
4343 return deserialized;
4346 /* Used in call_unhandled_exception_delegate */
4348 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4350 MONO_REQ_GC_UNSAFE_MODE;
4352 mono_error_init (error);
4355 MonoMethod *method = NULL;
4356 MonoBoolean is_terminating = TRUE;
4359 klass = mono_class_get_unhandled_exception_event_args_class ();
4360 mono_class_init (klass);
4362 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4363 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4367 args [1] = &is_terminating;
4369 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4370 return_val_if_nok (error, NULL);
4372 mono_runtime_invoke_checked (method, obj, args, error);
4373 return_val_if_nok (error, NULL);
4378 /* Used in mono_unhandled_exception */
4380 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4381 MONO_REQ_GC_UNSAFE_MODE;
4384 MonoObject *e = NULL;
4386 MonoDomain *current_domain = mono_domain_get ();
4388 if (domain != current_domain)
4389 mono_domain_set_internal_with_options (domain, FALSE);
4391 g_assert (domain == mono_object_domain (domain->domain));
4393 if (mono_object_domain (exc) != domain) {
4395 exc = mono_object_xdomain_representation (exc, domain, &error);
4397 if (!is_ok (&error)) {
4398 MonoError inner_error;
4399 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4400 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4401 mono_error_assert_ok (&inner_error);
4403 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4404 "System.Runtime.Serialization", "SerializationException",
4405 "Could not serialize unhandled exception.");
4409 g_assert (mono_object_domain (exc) == domain);
4411 pa [0] = domain->domain;
4412 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4413 mono_error_assert_ok (&error);
4414 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4415 if (!is_ok (&error)) {
4417 e = (MonoObject*)mono_error_convert_to_exception (&error);
4419 mono_error_cleanup (&error);
4422 if (domain != current_domain)
4423 mono_domain_set_internal_with_options (current_domain, FALSE);
4426 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4427 if (!mono_error_ok (&error)) {
4428 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4429 mono_error_cleanup (&error);
4431 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4437 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4440 * mono_runtime_unhandled_exception_policy_set:
4441 * @policy: the new policy
4443 * This is a VM internal routine.
4445 * Sets the runtime policy for handling unhandled exceptions.
4448 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4449 runtime_unhandled_exception_policy = policy;
4453 * mono_runtime_unhandled_exception_policy_get:
4455 * This is a VM internal routine.
4457 * Gets the runtime policy for handling unhandled exceptions.
4459 MonoRuntimeUnhandledExceptionPolicy
4460 mono_runtime_unhandled_exception_policy_get (void) {
4461 return runtime_unhandled_exception_policy;
4465 * mono_unhandled_exception:
4466 * @exc: exception thrown
4468 * This is a VM internal routine.
4470 * We call this function when we detect an unhandled exception
4471 * in the default domain.
4473 * It invokes the * UnhandledException event in AppDomain or prints
4474 * a warning to the console
4477 mono_unhandled_exception (MonoObject *exc)
4479 MONO_REQ_GC_UNSAFE_MODE;
4482 MonoClassField *field;
4483 MonoDomain *current_domain, *root_domain;
4484 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4486 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4489 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4492 current_domain = mono_domain_get ();
4493 root_domain = mono_get_root_domain ();
4495 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4496 mono_error_assert_ok (&error);
4497 if (current_domain != root_domain) {
4498 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4499 mono_error_assert_ok (&error);
4502 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4503 mono_print_unhandled_exception (exc);
4505 /* unhandled exception callbacks must not be aborted */
4506 mono_threads_begin_abort_protected_block ();
4507 if (root_appdomain_delegate)
4508 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4509 if (current_appdomain_delegate)
4510 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4511 mono_threads_end_abort_protected_block ();
4514 /* set exitcode only if we will abort the process */
4515 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4516 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4518 mono_environment_exitcode_set (1);
4523 * mono_runtime_exec_managed_code:
4524 * @domain: Application domain
4525 * @main_func: function to invoke from the execution thread
4526 * @main_args: parameter to the main_func
4528 * Launch a new thread to execute a function
4530 * main_func is called back from the thread with main_args as the
4531 * parameter. The callback function is expected to start Main()
4532 * eventually. This function then waits for all managed threads to
4534 * It is not necesseray anymore to execute managed code in a subthread,
4535 * so this function should not be used anymore by default: just
4536 * execute the code and then call mono_thread_manage ().
4539 mono_runtime_exec_managed_code (MonoDomain *domain,
4540 MonoMainThreadFunc main_func,
4544 mono_thread_create_checked (domain, main_func, main_args, &error);
4545 mono_error_assert_ok (&error);
4547 mono_thread_manage ();
4551 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4553 MonoInternalThread* thread = mono_thread_internal_current ();
4554 MonoCustomAttrInfo* cinfo;
4555 gboolean has_stathread_attribute;
4557 if (!domain->entry_assembly) {
4559 MonoAssembly *assembly;
4561 assembly = method->klass->image->assembly;
4562 domain->entry_assembly = assembly;
4563 /* Domains created from another domain already have application_base and configuration_file set */
4564 if (domain->setup->application_base == NULL) {
4565 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4568 if (domain->setup->configuration_file == NULL) {
4569 str = g_strconcat (assembly->image->name, ".config", NULL);
4570 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4572 mono_domain_set_options_from_config (domain);
4576 MonoError cattr_error;
4577 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4578 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4580 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4582 mono_custom_attrs_free (cinfo);
4584 has_stathread_attribute = FALSE;
4586 if (has_stathread_attribute) {
4587 thread->apartment_state = ThreadApartmentState_STA;
4589 thread->apartment_state = ThreadApartmentState_MTA;
4591 mono_thread_init_apartment_state ();
4596 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4598 MONO_REQ_GC_UNSAFE_MODE;
4603 mono_error_init (error);
4608 /* FIXME: check signature of method */
4609 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4611 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4613 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4616 mono_environment_exitcode_set (rval);
4618 mono_runtime_invoke_checked (method, NULL, pa, error);
4630 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4632 MONO_REQ_GC_UNSAFE_MODE;
4642 /* FIXME: check signature of method */
4643 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4644 MonoError inner_error;
4646 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4647 if (*exc == NULL && !mono_error_ok (&inner_error))
4648 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4650 mono_error_cleanup (&inner_error);
4653 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4657 mono_environment_exitcode_set (rval);
4659 MonoError inner_error;
4660 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4661 if (*exc == NULL && !mono_error_ok (&inner_error))
4662 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4664 mono_error_cleanup (&inner_error);
4669 /* If the return type of Main is void, only
4670 * set the exitcode if an exception was thrown
4671 * (we don't want to blow away an
4672 * explicitly-set exit code)
4675 mono_environment_exitcode_set (rval);
4683 * Execute a standard Main() method (args doesn't contain the
4687 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4690 prepare_thread_to_exec_main (mono_object_domain (args), method);
4692 int rval = do_try_exec_main (method, args, exc);
4695 int rval = do_exec_main_checked (method, args, &error);
4696 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4702 * Execute a standard Main() method (args doesn't contain the
4705 * On failure sets @error
4708 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4710 mono_error_init (error);
4711 prepare_thread_to_exec_main (mono_object_domain (args), method);
4712 return do_exec_main_checked (method, args, error);
4716 * Execute a standard Main() method (args doesn't contain the
4719 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4722 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4724 prepare_thread_to_exec_main (mono_object_domain (args), method);
4725 return do_try_exec_main (method, args, exc);
4730 /** invoke_array_extract_argument:
4731 * @params: array of arguments to the method.
4732 * @i: the index of the argument to extract.
4733 * @t: ith type from the method signature.
4734 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4735 * @error: set on error.
4737 * Given an array of method arguments, return the ith one using the corresponding type
4738 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4740 * On failure sets @error and returns NULL.
4743 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4745 MonoType *t_orig = t;
4746 gpointer result = NULL;
4747 mono_error_init (error);
4752 case MONO_TYPE_BOOLEAN:
4755 case MONO_TYPE_CHAR:
4764 case MONO_TYPE_VALUETYPE:
4765 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4766 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4767 result = mono_array_get (params, MonoObject*, i);
4769 *has_byref_nullables = TRUE;
4771 /* MS seems to create the objects if a null is passed in */
4772 if (!mono_array_get (params, MonoObject*, i)) {
4773 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4774 return_val_if_nok (error, NULL);
4775 mono_array_setref (params, i, o);
4780 * We can't pass the unboxed vtype byref to the callee, since
4781 * that would mean the callee would be able to modify boxed
4782 * primitive types. So we (and MS) make a copy of the boxed
4783 * object, pass that to the callee, and replace the original
4784 * boxed object in the arg array with the copy.
4786 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4787 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4788 return_val_if_nok (error, NULL);
4789 mono_array_setref (params, i, copy);
4792 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4795 case MONO_TYPE_STRING:
4796 case MONO_TYPE_OBJECT:
4797 case MONO_TYPE_CLASS:
4798 case MONO_TYPE_ARRAY:
4799 case MONO_TYPE_SZARRAY:
4801 result = mono_array_addr (params, MonoObject*, i);
4802 // FIXME: I need to check this code path
4804 result = mono_array_get (params, MonoObject*, i);
4806 case MONO_TYPE_GENERICINST:
4808 t = &t->data.generic_class->container_class->this_arg;
4810 t = &t->data.generic_class->container_class->byval_arg;
4812 case MONO_TYPE_PTR: {
4815 /* The argument should be an IntPtr */
4816 arg = mono_array_get (params, MonoObject*, i);
4820 g_assert (arg->vtable->klass == mono_defaults.int_class);
4821 result = ((MonoIntPtr*)arg)->m_value;
4826 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4831 * mono_runtime_invoke_array:
4832 * @method: method to invoke
4833 * @obJ: object instance
4834 * @params: arguments to the method
4835 * @exc: exception information.
4837 * Invokes the method represented by @method on the object @obj.
4839 * obj is the 'this' pointer, it should be NULL for static
4840 * methods, a MonoObject* for object instances and a pointer to
4841 * the value type for value types.
4843 * The params array contains the arguments to the method with the
4844 * same convention: MonoObject* pointers for object instances and
4845 * pointers to the value type otherwise. The _invoke_array
4846 * variant takes a C# object[] as the params argument (MonoArray
4847 * *params): in this case the value types are boxed inside the
4848 * respective reference representation.
4850 * From unmanaged code you'll usually use the
4851 * mono_runtime_invoke_checked() variant.
4853 * Note that this function doesn't handle virtual methods for
4854 * you, it will exec the exact method you pass: we still need to
4855 * expose a function to lookup the derived class implementation
4856 * of a virtual method (there are examples of this in the code,
4859 * You can pass NULL as the exc argument if you don't want to
4860 * catch exceptions, otherwise, *exc will be set to the exception
4861 * thrown, if any. if an exception is thrown, you can't use the
4862 * MonoObject* result from the function.
4864 * If the method returns a value type, it is boxed in an object
4868 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4873 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4875 mono_error_cleanup (&error);
4878 if (!is_ok (&error))
4879 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4883 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4884 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4890 * mono_runtime_invoke_array_checked:
4891 * @method: method to invoke
4892 * @obJ: object instance
4893 * @params: arguments to the method
4894 * @error: set on failure.
4896 * Invokes the method represented by @method on the object @obj.
4898 * obj is the 'this' pointer, it should be NULL for static
4899 * methods, a MonoObject* for object instances and a pointer to
4900 * the value type for value types.
4902 * The params array contains the arguments to the method with the
4903 * same convention: MonoObject* pointers for object instances and
4904 * pointers to the value type otherwise. The _invoke_array
4905 * variant takes a C# object[] as the params argument (MonoArray
4906 * *params): in this case the value types are boxed inside the
4907 * respective reference representation.
4909 * From unmanaged code you'll usually use the
4910 * mono_runtime_invoke_checked() variant.
4912 * Note that this function doesn't handle virtual methods for
4913 * you, it will exec the exact method you pass: we still need to
4914 * expose a function to lookup the derived class implementation
4915 * of a virtual method (there are examples of this in the code,
4918 * On failure or exception, @error will be set. In that case, you
4919 * can't use the MonoObject* result from the function.
4921 * If the method returns a value type, it is boxed in an object
4925 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4928 mono_error_init (error);
4929 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4933 * mono_runtime_try_invoke_array:
4934 * @method: method to invoke
4935 * @obJ: object instance
4936 * @params: arguments to the method
4937 * @exc: exception information.
4938 * @error: set on failure.
4940 * Invokes the method represented by @method on the object @obj.
4942 * obj is the 'this' pointer, it should be NULL for static
4943 * methods, a MonoObject* for object instances and a pointer to
4944 * the value type for value types.
4946 * The params array contains the arguments to the method with the
4947 * same convention: MonoObject* pointers for object instances and
4948 * pointers to the value type otherwise. The _invoke_array
4949 * variant takes a C# object[] as the params argument (MonoArray
4950 * *params): in this case the value types are boxed inside the
4951 * respective reference representation.
4953 * From unmanaged code you'll usually use the
4954 * mono_runtime_invoke_checked() variant.
4956 * Note that this function doesn't handle virtual methods for
4957 * you, it will exec the exact method you pass: we still need to
4958 * expose a function to lookup the derived class implementation
4959 * of a virtual method (there are examples of this in the code,
4962 * You can pass NULL as the exc argument if you don't want to catch
4963 * exceptions, otherwise, *exc will be set to the exception thrown, if
4964 * any. On other failures, @error will be set. If an exception is
4965 * thrown or there's an error, you can't use the MonoObject* result
4966 * from the function.
4968 * If the method returns a value type, it is boxed in an object
4972 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4973 MonoObject **exc, MonoError *error)
4975 MONO_REQ_GC_UNSAFE_MODE;
4977 mono_error_init (error);
4979 MonoMethodSignature *sig = mono_method_signature (method);
4980 gpointer *pa = NULL;
4983 gboolean has_byref_nullables = FALSE;
4985 if (NULL != params) {
4986 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4987 for (i = 0; i < mono_array_length (params); i++) {
4988 MonoType *t = sig->params [i];
4989 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4990 return_val_if_nok (error, NULL);
4994 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4997 if (mono_class_is_nullable (method->klass)) {
4998 /* Need to create a boxed vtype instead */
5004 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5009 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5010 mono_error_assert_ok (error);
5011 g_assert (obj); /*maybe we should raise a TLE instead?*/
5012 #ifndef DISABLE_REMOTING
5013 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5014 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5017 if (method->klass->valuetype)
5018 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5021 } else if (method->klass->valuetype) {
5022 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5023 return_val_if_nok (error, NULL);
5027 mono_runtime_try_invoke (method, o, pa, exc, error);
5029 mono_runtime_invoke_checked (method, o, pa, error);
5032 return (MonoObject *)obj;
5034 if (mono_class_is_nullable (method->klass)) {
5035 MonoObject *nullable;
5037 /* Convert the unboxed vtype into a Nullable structure */
5038 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5039 return_val_if_nok (error, NULL);
5041 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5042 return_val_if_nok (error, NULL);
5043 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5044 obj = mono_object_unbox (nullable);
5047 /* obj must be already unboxed if needed */
5049 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5051 res = mono_runtime_invoke_checked (method, obj, pa, error);
5053 return_val_if_nok (error, NULL);
5055 if (sig->ret->type == MONO_TYPE_PTR) {
5056 MonoClass *pointer_class;
5057 static MonoMethod *box_method;
5059 MonoObject *box_exc;
5062 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5063 * convert it to a Pointer object.
5065 pointer_class = mono_class_get_pointer_class ();
5067 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5069 g_assert (res->vtable->klass == mono_defaults.int_class);
5070 box_args [0] = ((MonoIntPtr*)res)->m_value;
5071 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5072 return_val_if_nok (error, NULL);
5074 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5075 g_assert (box_exc == NULL);
5076 mono_error_assert_ok (error);
5079 if (has_byref_nullables) {
5081 * The runtime invoke wrapper already converted byref nullables back,
5082 * and stored them in pa, we just need to copy them back to the
5085 for (i = 0; i < mono_array_length (params); i++) {
5086 MonoType *t = sig->params [i];
5088 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5089 mono_array_setref (params, i, pa [i]);
5099 * @klass: the class of the object that we want to create
5101 * Returns: a newly created object whose definition is
5102 * looked up using @klass. This will not invoke any constructors,
5103 * so the consumer of this routine has to invoke any constructors on
5104 * its own to initialize the object.
5106 * It returns NULL on failure.
5109 mono_object_new (MonoDomain *domain, MonoClass *klass)
5111 MONO_REQ_GC_UNSAFE_MODE;
5115 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5117 mono_error_cleanup (&error);
5122 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5124 MONO_REQ_GC_UNSAFE_MODE;
5128 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5130 mono_error_set_pending_exception (&error);
5135 * mono_object_new_checked:
5136 * @klass: the class of the object that we want to create
5137 * @error: set on error
5139 * Returns: a newly created object whose definition is
5140 * looked up using @klass. This will not invoke any constructors,
5141 * so the consumer of this routine has to invoke any constructors on
5142 * its own to initialize the object.
5144 * It returns NULL on failure and sets @error.
5147 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5149 MONO_REQ_GC_UNSAFE_MODE;
5153 vtable = mono_class_vtable (domain, klass);
5154 g_assert (vtable); /* FIXME don't swallow the error */
5156 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5161 * mono_object_new_pinned:
5163 * Same as mono_object_new, but the returned object will be pinned.
5164 * For SGEN, these objects will only be freed at appdomain unload.
5167 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5169 MONO_REQ_GC_UNSAFE_MODE;
5173 mono_error_init (error);
5175 vtable = mono_class_vtable (domain, klass);
5176 g_assert (vtable); /* FIXME don't swallow the error */
5178 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5180 if (G_UNLIKELY (!o))
5181 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5182 else if (G_UNLIKELY (vtable->klass->has_finalize))
5183 mono_object_register_finalizer (o);
5189 * mono_object_new_specific:
5190 * @vtable: the vtable of the object that we want to create
5192 * Returns: A newly created object with class and domain specified
5196 mono_object_new_specific (MonoVTable *vtable)
5199 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5200 mono_error_cleanup (&error);
5206 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5208 MONO_REQ_GC_UNSAFE_MODE;
5212 mono_error_init (error);
5214 /* check for is_com_object for COM Interop */
5215 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5218 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5221 MonoClass *klass = mono_class_get_activation_services_class ();
5224 mono_class_init (klass);
5226 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5228 mono_error_set_not_supported (error, "Linked away.");
5231 vtable->domain->create_proxy_for_type_method = im;
5234 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5235 if (!mono_error_ok (error))
5238 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5239 if (!mono_error_ok (error))
5246 return mono_object_new_alloc_specific_checked (vtable, error);
5250 ves_icall_object_new_specific (MonoVTable *vtable)
5253 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5254 mono_error_set_pending_exception (&error);
5260 * mono_object_new_alloc_specific:
5261 * @vtable: virtual table for the object.
5263 * This function allocates a new `MonoObject` with the type derived
5264 * from the @vtable information. If the class of this object has a
5265 * finalizer, then the object will be tracked for finalization.
5267 * This method might raise an exception on errors. Use the
5268 * `mono_object_new_fast_checked` method if you want to manually raise
5271 * Returns: the allocated object.
5274 mono_object_new_alloc_specific (MonoVTable *vtable)
5277 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5278 mono_error_cleanup (&error);
5284 * mono_object_new_alloc_specific_checked:
5285 * @vtable: virtual table for the object.
5286 * @error: holds the error return value.
5288 * This function allocates a new `MonoObject` with the type derived
5289 * from the @vtable information. If the class of this object has a
5290 * finalizer, then the object will be tracked for finalization.
5292 * If there is not enough memory, the @error parameter will be set
5293 * and will contain a user-visible message with the amount of bytes
5294 * that were requested.
5296 * Returns: the allocated object, or NULL if there is not enough memory
5300 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5302 MONO_REQ_GC_UNSAFE_MODE;
5306 mono_error_init (error);
5308 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5310 if (G_UNLIKELY (!o))
5311 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5312 else if (G_UNLIKELY (vtable->klass->has_finalize))
5313 mono_object_register_finalizer (o);
5319 * mono_object_new_fast:
5320 * @vtable: virtual table for the object.
5322 * This function allocates a new `MonoObject` with the type derived
5323 * from the @vtable information. The returned object is not tracked
5324 * for finalization. If your object implements a finalizer, you should
5325 * use `mono_object_new_alloc_specific` instead.
5327 * This method might raise an exception on errors. Use the
5328 * `mono_object_new_fast_checked` method if you want to manually raise
5331 * Returns: the allocated object.
5334 mono_object_new_fast (MonoVTable *vtable)
5337 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5338 mono_error_cleanup (&error);
5344 * mono_object_new_fast_checked:
5345 * @vtable: virtual table for the object.
5346 * @error: holds the error return value.
5348 * This function allocates a new `MonoObject` with the type derived
5349 * from the @vtable information. The returned object is not tracked
5350 * for finalization. If your object implements a finalizer, you should
5351 * use `mono_object_new_alloc_specific_checked` instead.
5353 * If there is not enough memory, the @error parameter will be set
5354 * and will contain a user-visible message with the amount of bytes
5355 * that were requested.
5357 * Returns: the allocated object, or NULL if there is not enough memory
5361 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5363 MONO_REQ_GC_UNSAFE_MODE;
5367 mono_error_init (error);
5369 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5371 if (G_UNLIKELY (!o))
5372 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5378 ves_icall_object_new_fast (MonoVTable *vtable)
5381 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5382 mono_error_set_pending_exception (&error);
5388 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5390 MONO_REQ_GC_UNSAFE_MODE;
5394 mono_error_init (error);
5396 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5398 if (G_UNLIKELY (!o))
5399 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5400 else if (G_UNLIKELY (vtable->klass->has_finalize))
5401 mono_object_register_finalizer (o);
5407 * mono_class_get_allocation_ftn:
5409 * @for_box: the object will be used for boxing
5410 * @pass_size_in_words:
5412 * Return the allocation function appropriate for the given class.
5416 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5418 MONO_REQ_GC_NEUTRAL_MODE;
5420 *pass_size_in_words = FALSE;
5422 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5423 return ves_icall_object_new_specific;
5425 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5427 return ves_icall_object_new_fast;
5430 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5431 * of the overhead of parameter passing.
5434 *pass_size_in_words = TRUE;
5435 #ifdef GC_REDIRECT_TO_LOCAL
5436 return GC_local_gcj_fast_malloc;
5438 return GC_gcj_fast_malloc;
5443 return ves_icall_object_new_specific;
5447 * mono_object_new_from_token:
5448 * @image: Context where the type_token is hosted
5449 * @token: a token of the type that we want to create
5451 * Returns: A newly created object whose definition is
5452 * looked up using @token in the @image image
5455 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5457 MONO_REQ_GC_UNSAFE_MODE;
5463 klass = mono_class_get_checked (image, token, &error);
5464 mono_error_assert_ok (&error);
5466 result = mono_object_new_checked (domain, klass, &error);
5468 mono_error_cleanup (&error);
5475 * mono_object_clone:
5476 * @obj: the object to clone
5478 * Returns: A newly created object who is a shallow copy of @obj
5481 mono_object_clone (MonoObject *obj)
5484 MonoObject *o = mono_object_clone_checked (obj, &error);
5485 mono_error_cleanup (&error);
5491 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5493 MONO_REQ_GC_UNSAFE_MODE;
5498 mono_error_init (error);
5500 size = obj->vtable->klass->instance_size;
5502 if (obj->vtable->klass->rank)
5503 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5505 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5507 if (G_UNLIKELY (!o)) {
5508 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5512 /* If the object doesn't contain references this will do a simple memmove. */
5513 mono_gc_wbarrier_object_copy (o, obj);
5515 if (obj->vtable->klass->has_finalize)
5516 mono_object_register_finalizer (o);
5521 * mono_array_full_copy:
5522 * @src: source array to copy
5523 * @dest: destination array
5525 * Copies the content of one array to another with exactly the same type and size.
5528 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5530 MONO_REQ_GC_UNSAFE_MODE;
5533 MonoClass *klass = src->obj.vtable->klass;
5535 g_assert (klass == dest->obj.vtable->klass);
5537 size = mono_array_length (src);
5538 g_assert (size == mono_array_length (dest));
5539 size *= mono_array_element_size (klass);
5541 if (klass->element_class->valuetype) {
5542 if (klass->element_class->has_references)
5543 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5545 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5547 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5550 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5555 * mono_array_clone_in_domain:
5556 * @domain: the domain in which the array will be cloned into
5557 * @array: the array to clone
5558 * @error: set on error
5560 * This routine returns a copy of the array that is hosted on the
5561 * specified MonoDomain. On failure returns NULL and sets @error.
5564 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5566 MONO_REQ_GC_UNSAFE_MODE;
5571 MonoClass *klass = array->obj.vtable->klass;
5573 mono_error_init (error);
5575 if (array->bounds == NULL) {
5576 size = mono_array_length (array);
5577 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5578 return_val_if_nok (error, NULL);
5580 size *= mono_array_element_size (klass);
5582 if (klass->element_class->valuetype) {
5583 if (klass->element_class->has_references)
5584 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5586 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5588 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5591 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5596 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5597 size = mono_array_element_size (klass);
5598 for (i = 0; i < klass->rank; ++i) {
5599 sizes [i] = array->bounds [i].length;
5600 size *= array->bounds [i].length;
5601 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5603 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5604 return_val_if_nok (error, NULL);
5606 if (klass->element_class->valuetype) {
5607 if (klass->element_class->has_references)
5608 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5610 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5612 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5615 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5623 * @array: the array to clone
5625 * Returns: A newly created array who is a shallow copy of @array
5628 mono_array_clone (MonoArray *array)
5630 MONO_REQ_GC_UNSAFE_MODE;
5633 MonoArray *result = mono_array_clone_checked (array, &error);
5634 mono_error_cleanup (&error);
5639 * mono_array_clone_checked:
5640 * @array: the array to clone
5641 * @error: set on error
5643 * Returns: A newly created array who is a shallow copy of @array. On
5644 * failure returns NULL and sets @error.
5647 mono_array_clone_checked (MonoArray *array, MonoError *error)
5650 MONO_REQ_GC_UNSAFE_MODE;
5651 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5654 /* helper macros to check for overflow when calculating the size of arrays */
5655 #ifdef MONO_BIG_ARRAYS
5656 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5657 #define MYGUINT_MAX MYGUINT64_MAX
5658 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5659 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5660 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5661 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5662 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5664 #define MYGUINT32_MAX 4294967295U
5665 #define MYGUINT_MAX MYGUINT32_MAX
5666 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5667 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5668 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5669 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5670 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5674 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5676 MONO_REQ_GC_NEUTRAL_MODE;
5680 byte_len = mono_array_element_size (klass);
5681 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5684 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5686 byte_len += MONO_SIZEOF_MONO_ARRAY;
5694 * mono_array_new_full:
5695 * @domain: domain where the object is created
5696 * @array_class: array class
5697 * @lengths: lengths for each dimension in the array
5698 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5700 * This routine creates a new array objects with the given dimensions,
5701 * lower bounds and type.
5704 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5707 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5708 mono_error_cleanup (&error);
5714 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5716 MONO_REQ_GC_UNSAFE_MODE;
5718 uintptr_t byte_len = 0, len, bounds_size;
5721 MonoArrayBounds *bounds;
5725 mono_error_init (error);
5727 if (!array_class->inited)
5728 mono_class_init (array_class);
5732 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5733 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5735 if (len > MONO_ARRAY_MAX_INDEX) {
5736 mono_error_set_generic_error (error, "System", "OverflowException", "");
5741 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5743 for (i = 0; i < array_class->rank; ++i) {
5744 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5745 mono_error_set_generic_error (error, "System", "OverflowException", "");
5748 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5749 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5756 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5757 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5763 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5764 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5767 byte_len = (byte_len + 3) & ~3;
5768 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5769 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5772 byte_len += bounds_size;
5775 * Following three lines almost taken from mono_object_new ():
5776 * they need to be kept in sync.
5778 vtable = mono_class_vtable_full (domain, array_class, error);
5779 return_val_if_nok (error, NULL);
5782 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5784 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5786 if (G_UNLIKELY (!o)) {
5787 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5791 array = (MonoArray*)o;
5793 bounds = array->bounds;
5796 for (i = 0; i < array_class->rank; ++i) {
5797 bounds [i].length = lengths [i];
5799 bounds [i].lower_bound = lower_bounds [i];
5808 * @domain: domain where the object is created
5809 * @eclass: element class
5810 * @n: number of array elements
5812 * This routine creates a new szarray with @n elements of type @eclass.
5815 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5817 MONO_REQ_GC_UNSAFE_MODE;
5820 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5821 mono_error_cleanup (&error);
5826 * mono_array_new_checked:
5827 * @domain: domain where the object is created
5828 * @eclass: element class
5829 * @n: number of array elements
5830 * @error: set on error
5832 * This routine creates a new szarray with @n elements of type @eclass.
5833 * On failure returns NULL and sets @error.
5836 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5840 mono_error_init (error);
5842 ac = mono_array_class_get (eclass, 1);
5845 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5846 return_val_if_nok (error, NULL);
5848 return mono_array_new_specific_checked (vtable, n, error);
5852 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5855 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5856 mono_error_set_pending_exception (&error);
5862 * mono_array_new_specific:
5863 * @vtable: a vtable in the appropriate domain for an initialized class
5864 * @n: number of array elements
5866 * This routine is a fast alternative to mono_array_new() for code which
5867 * can be sure about the domain it operates in.
5870 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5873 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5874 mono_error_cleanup (&error);
5880 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5882 MONO_REQ_GC_UNSAFE_MODE;
5887 mono_error_init (error);
5889 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5890 mono_error_set_generic_error (error, "System", "OverflowException", "");
5894 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5895 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5898 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5900 if (G_UNLIKELY (!o)) {
5901 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5905 return (MonoArray*)o;
5909 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5912 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5913 mono_error_set_pending_exception (&error);
5919 * mono_string_new_utf16:
5920 * @text: a pointer to an utf16 string
5921 * @len: the length of the string
5923 * Returns: A newly created string object which contains @text.
5926 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5928 MONO_REQ_GC_UNSAFE_MODE;
5931 MonoString *res = NULL;
5932 res = mono_string_new_utf16_checked (domain, text, len, &error);
5933 mono_error_cleanup (&error);
5939 * mono_string_new_utf16_checked:
5940 * @text: a pointer to an utf16 string
5941 * @len: the length of the string
5942 * @error: written on error.
5944 * Returns: A newly created string object which contains @text.
5945 * On error, returns NULL and sets @error.
5948 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5950 MONO_REQ_GC_UNSAFE_MODE;
5954 mono_error_init (error);
5956 s = mono_string_new_size_checked (domain, len, error);
5958 memcpy (mono_string_chars (s), text, len * 2);
5964 * mono_string_new_utf32:
5965 * @text: a pointer to an utf32 string
5966 * @len: the length of the string
5967 * @error: set on failure.
5969 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5972 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5974 MONO_REQ_GC_UNSAFE_MODE;
5977 mono_unichar2 *utf16_output = NULL;
5978 gint32 utf16_len = 0;
5979 GError *gerror = NULL;
5980 glong items_written;
5982 mono_error_init (error);
5983 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5986 g_error_free (gerror);
5988 while (utf16_output [utf16_len]) utf16_len++;
5990 s = mono_string_new_size_checked (domain, utf16_len, error);
5991 return_val_if_nok (error, NULL);
5993 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5995 g_free (utf16_output);
6001 * mono_string_new_utf32:
6002 * @text: a pointer to an utf32 string
6003 * @len: the length of the string
6005 * Returns: A newly created string object which contains @text.
6008 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6011 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6012 mono_error_cleanup (&error);
6017 * mono_string_new_size:
6018 * @text: a pointer to an utf16 string
6019 * @len: the length of the string
6021 * Returns: A newly created string object of @len
6024 mono_string_new_size (MonoDomain *domain, gint32 len)
6027 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6028 mono_error_cleanup (&error);
6034 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6036 MONO_REQ_GC_UNSAFE_MODE;
6042 mono_error_init (error);
6044 /* check for overflow */
6045 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6046 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6050 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6051 g_assert (size > 0);
6053 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6056 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6058 if (G_UNLIKELY (!s)) {
6059 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6067 * mono_string_new_len:
6068 * @text: a pointer to an utf8 string
6069 * @length: number of bytes in @text to consider
6071 * Returns: A newly created string object which contains @text.
6074 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6076 MONO_REQ_GC_UNSAFE_MODE;
6079 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6080 mono_error_cleanup (&error);
6085 * mono_string_new_len_checked:
6086 * @text: a pointer to an utf8 string
6087 * @length: number of bytes in @text to consider
6088 * @error: set on error
6090 * Returns: A newly created string object which contains @text. On
6091 * failure returns NULL and sets @error.
6094 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6096 MONO_REQ_GC_UNSAFE_MODE;
6098 mono_error_init (error);
6100 GError *eg_error = NULL;
6101 MonoString *o = NULL;
6103 glong items_written;
6105 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6108 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6110 g_error_free (eg_error);
6119 * @text: a pointer to an utf8 string
6121 * Returns: A newly created string object which contains @text.
6123 * This function asserts if it cannot allocate a new string.
6125 * @deprecated Use mono_string_new_checked in new code.
6128 mono_string_new (MonoDomain *domain, const char *text)
6131 MonoString *res = NULL;
6132 res = mono_string_new_checked (domain, text, &error);
6133 mono_error_assert_ok (&error);
6138 * mono_string_new_checked:
6139 * @text: a pointer to an utf8 string
6140 * @merror: set on error
6142 * Returns: A newly created string object which contains @text.
6143 * On error returns NULL and sets @merror.
6146 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6148 MONO_REQ_GC_UNSAFE_MODE;
6150 GError *eg_error = NULL;
6151 MonoString *o = NULL;
6153 glong items_written;
6156 mono_error_init (error);
6160 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6163 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6165 g_error_free (eg_error);
6169 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6174 MonoString *o = NULL;
6176 if (!g_utf8_validate (text, -1, &end)) {
6177 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6181 len = g_utf8_strlen (text, -1);
6182 o = mono_string_new_size_checked (domain, len, error);
6185 str = mono_string_chars (o);
6187 while (text < end) {
6188 *str++ = g_utf8_get_char (text);
6189 text = g_utf8_next_char (text);
6198 * mono_string_new_wrapper:
6199 * @text: pointer to utf8 characters.
6201 * Helper function to create a string object from @text in the current domain.
6204 mono_string_new_wrapper (const char *text)
6206 MONO_REQ_GC_UNSAFE_MODE;
6208 MonoDomain *domain = mono_domain_get ();
6211 return mono_string_new (domain, text);
6218 * @class: the class of the value
6219 * @value: a pointer to the unboxed data
6221 * Returns: A newly created object which contains @value.
6224 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6227 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6228 mono_error_cleanup (&error);
6233 * mono_value_box_checked:
6234 * @domain: the domain of the new object
6235 * @class: the class of the value
6236 * @value: a pointer to the unboxed data
6237 * @error: set on error
6239 * Returns: A newly created object which contains @value. On failure
6240 * returns NULL and sets @error.
6243 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6245 MONO_REQ_GC_UNSAFE_MODE;
6250 mono_error_init (error);
6252 g_assert (klass->valuetype);
6253 if (mono_class_is_nullable (klass))
6254 return mono_nullable_box ((guint8 *)value, klass, error);
6256 vtable = mono_class_vtable (domain, klass);
6259 size = mono_class_instance_size (klass);
6260 res = mono_object_new_alloc_specific_checked (vtable, error);
6261 return_val_if_nok (error, NULL);
6263 size = size - sizeof (MonoObject);
6266 g_assert (size == mono_class_value_size (klass, NULL));
6267 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6269 #if NO_UNALIGNED_ACCESS
6270 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6274 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6277 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6280 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6283 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6286 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6290 if (klass->has_finalize) {
6291 mono_object_register_finalizer (res);
6292 return_val_if_nok (error, NULL);
6299 * @dest: destination pointer
6300 * @src: source pointer
6301 * @klass: a valuetype class
6303 * Copy a valuetype from @src to @dest. This function must be used
6304 * when @klass contains references fields.
6307 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6309 MONO_REQ_GC_UNSAFE_MODE;
6311 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6315 * mono_value_copy_array:
6316 * @dest: destination array
6317 * @dest_idx: index in the @dest array
6318 * @src: source pointer
6319 * @count: number of items
6321 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6322 * This function must be used when @klass contains references fields.
6323 * Overlap is handled.
6326 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6328 MONO_REQ_GC_UNSAFE_MODE;
6330 int size = mono_array_element_size (dest->obj.vtable->klass);
6331 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6332 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6333 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6337 * mono_object_get_domain:
6338 * @obj: object to query
6340 * Returns: the MonoDomain where the object is hosted
6343 mono_object_get_domain (MonoObject *obj)
6345 MONO_REQ_GC_UNSAFE_MODE;
6347 return mono_object_domain (obj);
6351 * mono_object_get_class:
6352 * @obj: object to query
6354 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6356 * Returns: the MonoClass of the object.
6359 mono_object_get_class (MonoObject *obj)
6361 MONO_REQ_GC_UNSAFE_MODE;
6363 return mono_object_class (obj);
6366 * mono_object_get_size:
6367 * @o: object to query
6369 * Returns: the size, in bytes, of @o
6372 mono_object_get_size (MonoObject* o)
6374 MONO_REQ_GC_UNSAFE_MODE;
6376 MonoClass* klass = mono_object_class (o);
6377 if (klass == mono_defaults.string_class) {
6378 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6379 } else if (o->vtable->rank) {
6380 MonoArray *array = (MonoArray*)o;
6381 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6382 if (array->bounds) {
6385 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6389 return mono_class_instance_size (klass);
6394 * mono_object_unbox:
6395 * @obj: object to unbox
6397 * Returns: a pointer to the start of the valuetype boxed in this
6400 * This method will assert if the object passed is not a valuetype.
6403 mono_object_unbox (MonoObject *obj)
6405 MONO_REQ_GC_UNSAFE_MODE;
6407 /* add assert for valuetypes? */
6408 g_assert (obj->vtable->klass->valuetype);
6409 return ((char*)obj) + sizeof (MonoObject);
6413 * mono_object_isinst:
6415 * @klass: a pointer to a class
6417 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6420 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6422 MONO_REQ_GC_UNSAFE_MODE;
6425 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6426 mono_error_cleanup (&error);
6432 * mono_object_isinst_checked:
6434 * @klass: a pointer to a class
6435 * @error: set on error
6437 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6438 * On failure returns NULL and sets @error.
6441 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6443 MONO_REQ_GC_UNSAFE_MODE;
6445 mono_error_init (error);
6447 MonoObject *result = NULL;
6450 mono_class_init (klass);
6452 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6453 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6460 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6464 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6466 MONO_REQ_GC_UNSAFE_MODE;
6469 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6470 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6475 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6477 MONO_REQ_GC_UNSAFE_MODE;
6481 mono_error_init (error);
6488 if (mono_class_is_interface (klass)) {
6489 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6493 /* casting an array one of the invariant interfaces that must act as such */
6494 if (klass->is_array_special_interface) {
6495 if (mono_class_is_assignable_from (klass, vt->klass))
6499 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6500 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6503 MonoClass *oklass = vt->klass;
6504 if (mono_class_is_transparent_proxy (oklass))
6505 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6507 mono_class_setup_supertypes (klass);
6508 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6511 #ifndef DISABLE_REMOTING
6512 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6514 MonoDomain *domain = mono_domain_get ();
6516 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6517 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6518 MonoMethod *im = NULL;
6521 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6523 mono_error_set_not_supported (error, "Linked away.");
6526 im = mono_object_get_virtual_method (rp, im);
6529 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6530 return_val_if_nok (error, NULL);
6533 res = mono_runtime_invoke_checked (im, rp, pa, error);
6534 return_val_if_nok (error, NULL);
6536 if (*(MonoBoolean *) mono_object_unbox(res)) {
6537 /* Update the vtable of the remote type, so it can safely cast to this new type */
6538 mono_upgrade_remote_class (domain, obj, klass, error);
6539 return_val_if_nok (error, NULL);
6543 #endif /* DISABLE_REMOTING */
6548 * mono_object_castclass_mbyref:
6550 * @klass: a pointer to a class
6552 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6555 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6557 MONO_REQ_GC_UNSAFE_MODE;
6560 if (!obj) return NULL;
6561 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6562 mono_error_cleanup (&error);
6567 MonoDomain *orig_domain;
6573 str_lookup (MonoDomain *domain, gpointer user_data)
6575 MONO_REQ_GC_UNSAFE_MODE;
6577 LDStrInfo *info = (LDStrInfo *)user_data;
6578 if (info->res || domain == info->orig_domain)
6580 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6584 mono_string_get_pinned (MonoString *str, MonoError *error)
6586 MONO_REQ_GC_UNSAFE_MODE;
6588 mono_error_init (error);
6590 /* We only need to make a pinned version of a string if this is a moving GC */
6591 if (!mono_gc_is_moving ())
6595 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6596 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6598 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6599 news->length = mono_string_length (str);
6601 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6607 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6609 MONO_REQ_GC_UNSAFE_MODE;
6611 MonoGHashTable *ldstr_table;
6612 MonoString *s, *res;
6615 mono_error_init (error);
6617 domain = ((MonoObject *)str)->vtable->domain;
6618 ldstr_table = domain->ldstr_table;
6620 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6626 /* Allocate outside the lock */
6628 s = mono_string_get_pinned (str, error);
6629 return_val_if_nok (error, NULL);
6632 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6637 mono_g_hash_table_insert (ldstr_table, s, s);
6642 LDStrInfo ldstr_info;
6643 ldstr_info.orig_domain = domain;
6644 ldstr_info.ins = str;
6645 ldstr_info.res = NULL;
6647 mono_domain_foreach (str_lookup, &ldstr_info);
6648 if (ldstr_info.res) {
6650 * the string was already interned in some other domain:
6651 * intern it in the current one as well.
6653 mono_g_hash_table_insert (ldstr_table, str, str);
6663 * mono_string_is_interned:
6664 * @o: String to probe
6666 * Returns whether the string has been interned.
6669 mono_string_is_interned (MonoString *o)
6672 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6673 /* This function does not fail. */
6674 mono_error_assert_ok (&error);
6679 * mono_string_intern:
6680 * @o: String to intern
6682 * Interns the string passed.
6683 * Returns: The interned string.
6686 mono_string_intern (MonoString *str)
6689 MonoString *result = mono_string_intern_checked (str, &error);
6690 mono_error_assert_ok (&error);
6695 * mono_string_intern_checked:
6696 * @o: String to intern
6697 * @error: set on error.
6699 * Interns the string passed.
6700 * Returns: The interned string. On failure returns NULL and sets @error
6703 mono_string_intern_checked (MonoString *str, MonoError *error)
6705 MONO_REQ_GC_UNSAFE_MODE;
6707 mono_error_init (error);
6709 return mono_string_is_interned_lookup (str, TRUE, error);
6714 * @domain: the domain where the string will be used.
6715 * @image: a metadata context
6716 * @idx: index into the user string table.
6718 * Implementation for the ldstr opcode.
6719 * Returns: a loaded string from the @image/@idx combination.
6722 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6725 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6726 mono_error_cleanup (&error);
6731 * mono_ldstr_checked:
6732 * @domain: the domain where the string will be used.
6733 * @image: a metadata context
6734 * @idx: index into the user string table.
6735 * @error: set on error.
6737 * Implementation for the ldstr opcode.
6738 * Returns: a loaded string from the @image/@idx combination.
6739 * On failure returns NULL and sets @error.
6742 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6744 MONO_REQ_GC_UNSAFE_MODE;
6745 mono_error_init (error);
6747 if (image->dynamic) {
6748 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6751 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6752 return NULL; /*FIXME we should probably be raising an exception here*/
6753 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6759 * mono_ldstr_metadata_sig
6760 * @domain: the domain for the string
6761 * @sig: the signature of a metadata string
6762 * @error: set on error
6764 * Returns: a MonoString for a string stored in the metadata. On
6765 * failure returns NULL and sets @error.
6768 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6770 MONO_REQ_GC_UNSAFE_MODE;
6772 mono_error_init (error);
6773 const char *str = sig;
6774 MonoString *o, *interned;
6777 len2 = mono_metadata_decode_blob_size (str, &str);
6780 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6781 return_val_if_nok (error, NULL);
6782 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6785 guint16 *p2 = (guint16*)mono_string_chars (o);
6786 for (i = 0; i < len2; ++i) {
6787 *p2 = GUINT16_FROM_LE (*p2);
6793 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6796 return interned; /* o will get garbage collected */
6798 o = mono_string_get_pinned (o, error);
6801 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6803 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6815 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6819 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6825 GError *gerror = NULL;
6827 mono_error_init (error);
6829 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6830 return NULL; /*FIXME we should probably be raising an exception here*/
6831 str = mono_metadata_user_string (image, idx);
6833 len2 = mono_metadata_decode_blob_size (str, &str);
6836 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6838 mono_error_set_argument (error, "string", "%s", gerror->message);
6839 g_error_free (gerror);
6842 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6843 if (len2 > written) {
6844 /* allocate the total length and copy the part of the string that has been converted */
6845 char *as2 = (char *)g_malloc0 (len2);
6846 memcpy (as2, as, written);
6855 * mono_string_to_utf8:
6856 * @s: a System.String
6858 * Returns the UTF8 representation for @s.
6859 * The resulting buffer needs to be freed with mono_free().
6861 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6864 mono_string_to_utf8 (MonoString *s)
6866 MONO_REQ_GC_UNSAFE_MODE;
6869 char *result = mono_string_to_utf8_checked (s, &error);
6871 if (!is_ok (&error)) {
6872 mono_error_cleanup (&error);
6879 * mono_string_to_utf8_checked:
6880 * @s: a System.String
6881 * @error: a MonoError.
6883 * Converts a MonoString to its UTF8 representation. May fail; check
6884 * @error to determine whether the conversion was successful.
6885 * The resulting buffer should be freed with mono_free().
6888 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6890 MONO_REQ_GC_UNSAFE_MODE;
6894 GError *gerror = NULL;
6896 mono_error_init (error);
6902 return g_strdup ("");
6904 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6906 mono_error_set_argument (error, "string", "%s", gerror->message);
6907 g_error_free (gerror);
6910 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6911 if (s->length > written) {
6912 /* allocate the total length and copy the part of the string that has been converted */
6913 char *as2 = (char *)g_malloc0 (s->length);
6914 memcpy (as2, as, written);
6923 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6925 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6929 * mono_string_to_utf8_ignore:
6932 * Converts a MonoString to its UTF8 representation. Will ignore
6933 * invalid surrogate pairs.
6934 * The resulting buffer should be freed with mono_free().
6938 mono_string_to_utf8_ignore (MonoString *s)
6940 MONO_REQ_GC_UNSAFE_MODE;
6949 return g_strdup ("");
6951 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6953 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6954 if (s->length > written) {
6955 /* allocate the total length and copy the part of the string that has been converted */
6956 char *as2 = (char *)g_malloc0 (s->length);
6957 memcpy (as2, as, written);
6966 * mono_string_to_utf8_image_ignore:
6967 * @s: a System.String
6969 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6972 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6974 MONO_REQ_GC_UNSAFE_MODE;
6976 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6980 * mono_string_to_utf8_mp_ignore:
6981 * @s: a System.String
6983 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6986 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6988 MONO_REQ_GC_UNSAFE_MODE;
6990 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6995 * mono_string_to_utf16:
6998 * Return an null-terminated array of the utf-16 chars
6999 * contained in @s. The result must be freed with g_free().
7000 * This is a temporary helper until our string implementation
7001 * is reworked to always include the null terminating char.
7004 mono_string_to_utf16 (MonoString *s)
7006 MONO_REQ_GC_UNSAFE_MODE;
7013 as = (char *)g_malloc ((s->length * 2) + 2);
7014 as [(s->length * 2)] = '\0';
7015 as [(s->length * 2) + 1] = '\0';
7018 return (gunichar2 *)(as);
7021 memcpy (as, mono_string_chars(s), s->length * 2);
7022 return (gunichar2 *)(as);
7026 * mono_string_to_utf32:
7029 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7030 * contained in @s. The result must be freed with g_free().
7033 mono_string_to_utf32 (MonoString *s)
7035 MONO_REQ_GC_UNSAFE_MODE;
7037 mono_unichar4 *utf32_output = NULL;
7038 GError *error = NULL;
7039 glong items_written;
7044 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7047 g_error_free (error);
7049 return utf32_output;
7053 * mono_string_from_utf16:
7054 * @data: the UTF16 string (LPWSTR) to convert
7056 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7058 * Returns: a MonoString.
7061 mono_string_from_utf16 (gunichar2 *data)
7064 MonoString *result = mono_string_from_utf16_checked (data, &error);
7065 mono_error_cleanup (&error);
7070 * mono_string_from_utf16_checked:
7071 * @data: the UTF16 string (LPWSTR) to convert
7072 * @error: set on error
7074 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7076 * Returns: a MonoString. On failure sets @error and returns NULL.
7079 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7082 MONO_REQ_GC_UNSAFE_MODE;
7084 mono_error_init (error);
7085 MonoDomain *domain = mono_domain_get ();
7091 while (data [len]) len++;
7093 return mono_string_new_utf16_checked (domain, data, len, error);
7097 * mono_string_from_utf32:
7098 * @data: the UTF32 string (LPWSTR) to convert
7100 * Converts a UTF32 (UCS-4)to a MonoString.
7102 * Returns: a MonoString.
7105 mono_string_from_utf32 (mono_unichar4 *data)
7108 MonoString *result = mono_string_from_utf32_checked (data, &error);
7109 mono_error_cleanup (&error);
7114 * mono_string_from_utf32_checked:
7115 * @data: the UTF32 string (LPWSTR) to convert
7116 * @error: set on error
7118 * Converts a UTF32 (UCS-4)to a MonoString.
7120 * Returns: a MonoString. On failure returns NULL and sets @error.
7123 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7125 MONO_REQ_GC_UNSAFE_MODE;
7127 mono_error_init (error);
7128 MonoString* result = NULL;
7129 mono_unichar2 *utf16_output = NULL;
7130 GError *gerror = NULL;
7131 glong items_written;
7137 while (data [len]) len++;
7139 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7142 g_error_free (gerror);
7144 result = mono_string_from_utf16_checked (utf16_output, error);
7145 g_free (utf16_output);
7150 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7152 MONO_REQ_GC_UNSAFE_MODE;
7159 r = mono_string_to_utf8_ignore (s);
7161 r = mono_string_to_utf8_checked (s, error);
7162 if (!mono_error_ok (error))
7169 len = strlen (r) + 1;
7171 mp_s = (char *)mono_mempool_alloc (mp, len);
7173 mp_s = (char *)mono_image_alloc (image, len);
7175 memcpy (mp_s, r, len);
7183 * mono_string_to_utf8_image:
7184 * @s: a System.String
7186 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7189 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7191 MONO_REQ_GC_UNSAFE_MODE;
7193 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7197 * mono_string_to_utf8_mp:
7198 * @s: a System.String
7200 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7203 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7205 MONO_REQ_GC_UNSAFE_MODE;
7207 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7211 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7214 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7216 eh_callbacks = *cbs;
7219 MonoRuntimeExceptionHandlingCallbacks *
7220 mono_get_eh_callbacks (void)
7222 return &eh_callbacks;
7226 * mono_raise_exception:
7227 * @ex: exception object
7229 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7232 mono_raise_exception (MonoException *ex)
7234 MONO_REQ_GC_UNSAFE_MODE;
7237 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7238 * that will cause gcc to omit the function epilog, causing problems when
7239 * the JIT tries to walk the stack, since the return address on the stack
7240 * will point into the next function in the executable, not this one.
7242 eh_callbacks.mono_raise_exception (ex);
7246 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7248 MONO_REQ_GC_UNSAFE_MODE;
7250 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7254 * mono_wait_handle_new:
7255 * @domain: Domain where the object will be created
7256 * @handle: Handle for the wait handle
7257 * @error: set on error.
7259 * Returns: A new MonoWaitHandle created in the given domain for the
7260 * given handle. On failure returns NULL and sets @rror.
7263 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7265 MONO_REQ_GC_UNSAFE_MODE;
7267 MonoWaitHandle *res;
7268 gpointer params [1];
7269 static MonoMethod *handle_set;
7271 mono_error_init (error);
7272 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7273 return_val_if_nok (error, NULL);
7275 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7277 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7279 params [0] = &handle;
7281 mono_runtime_invoke_checked (handle_set, res, params, error);
7286 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7288 MONO_REQ_GC_UNSAFE_MODE;
7290 static MonoClassField *f_safe_handle = NULL;
7293 if (!f_safe_handle) {
7294 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7295 g_assert (f_safe_handle);
7298 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7304 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7306 MONO_REQ_GC_UNSAFE_MODE;
7308 RuntimeInvokeFunction runtime_invoke;
7310 mono_error_init (error);
7312 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7313 MonoMethod *method = mono_get_context_capture_method ();
7314 MonoMethod *wrapper;
7317 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7318 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7319 return_val_if_nok (error, NULL);
7320 domain->capture_context_method = mono_compile_method_checked (method, error);
7321 return_val_if_nok (error, NULL);
7324 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7326 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7329 * mono_async_result_new:
7330 * @domain:domain where the object will be created.
7331 * @handle: wait handle.
7332 * @state: state to pass to AsyncResult
7333 * @data: C closure data.
7334 * @error: set on error.
7336 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7337 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7338 * On failure returns NULL and sets @error.
7342 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7344 MONO_REQ_GC_UNSAFE_MODE;
7346 mono_error_init (error);
7347 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7348 return_val_if_nok (error, NULL);
7349 MonoObject *context = mono_runtime_capture_context (domain, error);
7350 return_val_if_nok (error, NULL);
7351 /* we must capture the execution context from the original thread */
7353 MONO_OBJECT_SETREF (res, execution_context, context);
7354 /* note: result may be null if the flow is suppressed */
7357 res->data = (void **)data;
7358 MONO_OBJECT_SETREF (res, object_data, object_data);
7359 MONO_OBJECT_SETREF (res, async_state, state);
7360 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7361 return_val_if_nok (error, NULL);
7363 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7365 res->sync_completed = FALSE;
7366 res->completed = FALSE;
7372 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7374 MONO_REQ_GC_UNSAFE_MODE;
7381 g_assert (ares->async_delegate);
7383 ac = (MonoAsyncCall*) ares->object_data;
7385 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7386 if (mono_error_set_pending_exception (&error))
7389 gpointer wait_event = NULL;
7391 ac->msg->exc = NULL;
7393 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7395 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7396 mono_threads_begin_abort_protected_block ();
7398 if (!ac->msg->exc) {
7399 MonoException *ex = mono_error_convert_to_exception (&error);
7400 ac->msg->exc = (MonoObject *)ex;
7402 mono_error_cleanup (&error);
7405 MONO_OBJECT_SETREF (ac, res, res);
7407 mono_monitor_enter ((MonoObject*) ares);
7408 ares->completed = 1;
7410 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7411 mono_monitor_exit ((MonoObject*) ares);
7413 if (wait_event != NULL)
7414 mono_w32event_set (wait_event);
7416 mono_error_init (&error); //the else branch would leave it in an undefined state
7418 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7420 mono_threads_end_abort_protected_block ();
7422 if (mono_error_set_pending_exception (&error))
7430 mono_message_init (MonoDomain *domain,
7431 MonoMethodMessage *this_obj,
7432 MonoReflectionMethod *method,
7433 MonoArray *out_args,
7436 MONO_REQ_GC_UNSAFE_MODE;
7438 static MonoMethod *init_message_method = NULL;
7440 if (!init_message_method) {
7441 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7442 g_assert (init_message_method != NULL);
7445 mono_error_init (error);
7446 /* FIXME set domain instead? */
7447 g_assert (domain == mono_domain_get ());
7454 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7455 return is_ok (error);
7458 #ifndef DISABLE_REMOTING
7460 * mono_remoting_invoke:
7461 * @real_proxy: pointer to a RealProxy object
7462 * @msg: The MonoMethodMessage to execute
7463 * @exc: used to store exceptions
7464 * @out_args: used to store output arguments
7466 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7467 * IMessage interface and it is not trivial to extract results from there. So
7468 * we call an helper method PrivateInvoke instead of calling
7469 * RealProxy::Invoke() directly.
7471 * Returns: the result object.
7474 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7476 MONO_REQ_GC_UNSAFE_MODE;
7479 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7484 mono_error_init (error);
7486 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7489 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7491 mono_error_set_not_supported (error, "Linked away.");
7494 real_proxy->vtable->domain->private_invoke_method = im;
7497 pa [0] = real_proxy;
7502 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7503 return_val_if_nok (error, NULL);
7510 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7511 MonoObject **exc, MonoArray **out_args, MonoError *error)
7513 MONO_REQ_GC_UNSAFE_MODE;
7515 static MonoClass *object_array_klass;
7516 mono_error_init (error);
7520 MonoMethodSignature *sig;
7522 int i, j, outarg_count = 0;
7524 #ifndef DISABLE_REMOTING
7525 if (target && mono_object_is_transparent_proxy (target)) {
7526 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7527 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7528 target = tp->rp->unwrapped_server;
7530 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7535 domain = mono_domain_get ();
7536 method = msg->method->method;
7537 sig = mono_method_signature (method);
7539 for (i = 0; i < sig->param_count; i++) {
7540 if (sig->params [i]->byref)
7544 if (!object_array_klass) {
7547 klass = mono_array_class_get (mono_defaults.object_class, 1);
7550 mono_memory_barrier ();
7551 object_array_klass = klass;
7554 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7555 return_val_if_nok (error, NULL);
7557 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7560 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7561 return_val_if_nok (error, NULL);
7563 for (i = 0, j = 0; i < sig->param_count; i++) {
7564 if (sig->params [i]->byref) {
7566 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7567 mono_array_setref (*out_args, j, arg);
7576 * prepare_to_string_method:
7578 * @target: Set to @obj or unboxed value if a valuetype
7580 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7583 prepare_to_string_method (MonoObject *obj, void **target)
7585 MONO_REQ_GC_UNSAFE_MODE;
7587 static MonoMethod *to_string = NULL;
7595 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7597 method = mono_object_get_virtual_method (obj, to_string);
7599 // Unbox value type if needed
7600 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7601 *target = mono_object_unbox (obj);
7607 * mono_object_to_string:
7609 * @exc: Any exception thrown by ToString (). May be NULL.
7611 * Returns: the result of calling ToString () on an object.
7614 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7617 MonoString *s = NULL;
7619 MonoMethod *method = prepare_to_string_method (obj, &target);
7621 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7622 if (*exc == NULL && !mono_error_ok (&error))
7623 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7625 mono_error_cleanup (&error);
7627 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7628 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7635 * mono_object_to_string_checked:
7637 * @error: Set on error.
7639 * Returns: the result of calling ToString () on an object. If the
7640 * method cannot be invoked or if it raises an exception, sets @error
7644 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7646 mono_error_init (error);
7648 MonoMethod *method = prepare_to_string_method (obj, &target);
7649 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7653 * mono_object_try_to_string:
7655 * @exc: Any exception thrown by ToString (). Must not be NULL.
7656 * @error: Set if method cannot be invoked.
7658 * Returns: the result of calling ToString () on an object. If the
7659 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7663 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7666 mono_error_init (error);
7668 MonoMethod *method = prepare_to_string_method (obj, &target);
7669 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7675 get_native_backtrace (MonoException *exc_raw)
7677 HANDLE_FUNCTION_ENTER ();
7678 MONO_HANDLE_DCL(MonoException, exc);
7679 char * trace = mono_exception_handle_get_native_backtrace (exc);
7680 HANDLE_FUNCTION_RETURN_VAL (trace);
7684 * mono_print_unhandled_exception:
7685 * @exc: The exception
7687 * Prints the unhandled exception.
7690 mono_print_unhandled_exception (MonoObject *exc)
7692 MONO_REQ_GC_UNSAFE_MODE;
7695 char *message = (char*)"";
7696 gboolean free_message = FALSE;
7699 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7700 message = g_strdup ("OutOfMemoryException");
7701 free_message = TRUE;
7702 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7703 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7704 free_message = TRUE;
7707 if (((MonoException*)exc)->native_trace_ips) {
7708 message = get_native_backtrace ((MonoException*)exc);
7709 free_message = TRUE;
7711 MonoObject *other_exc = NULL;
7712 str = mono_object_try_to_string (exc, &other_exc, &error);
7713 if (other_exc == NULL && !is_ok (&error))
7714 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7716 mono_error_cleanup (&error);
7718 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7719 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7721 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7722 original_backtrace, nested_backtrace);
7724 g_free (original_backtrace);
7725 g_free (nested_backtrace);
7726 free_message = TRUE;
7728 message = mono_string_to_utf8_checked (str, &error);
7729 if (!mono_error_ok (&error)) {
7730 mono_error_cleanup (&error);
7731 message = (char *) "";
7733 free_message = TRUE;
7740 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7741 * exc->vtable->klass->name, message);
7743 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7750 * mono_delegate_ctor_with_method:
7751 * @this: pointer to an uninitialized delegate object
7752 * @target: target object
7753 * @addr: pointer to native code
7755 * @error: set on error.
7757 * Initialize a delegate and sets a specific method, not the one
7758 * associated with addr. This is useful when sharing generic code.
7759 * In that case addr will most probably not be associated with the
7760 * correct instantiation of the method.
7761 * On failure returns FALSE and sets @error.
7764 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7766 MONO_REQ_GC_UNSAFE_MODE;
7768 mono_error_init (error);
7769 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7771 g_assert (this_obj);
7774 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7777 delegate->method = method;
7779 mono_stats.delegate_creations++;
7781 #ifndef DISABLE_REMOTING
7782 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7784 method = mono_marshal_get_remoting_invoke (method);
7785 delegate->method_ptr = mono_compile_method_checked (method, error);
7786 return_val_if_nok (error, FALSE);
7787 MONO_OBJECT_SETREF (delegate, target, target);
7791 delegate->method_ptr = addr;
7792 MONO_OBJECT_SETREF (delegate, target, target);
7795 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7796 if (callbacks.init_delegate)
7797 callbacks.init_delegate (delegate);
7802 * mono_delegate_ctor:
7803 * @this: pointer to an uninitialized delegate object
7804 * @target: target object
7805 * @addr: pointer to native code
7806 * @error: set on error.
7808 * This is used to initialize a delegate.
7809 * On failure returns FALSE and sets @error.
7812 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7814 MONO_REQ_GC_UNSAFE_MODE;
7816 mono_error_init (error);
7817 MonoDomain *domain = mono_domain_get ();
7819 MonoMethod *method = NULL;
7823 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7825 if (!ji && domain != mono_get_root_domain ())
7826 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7828 method = mono_jit_info_get_method (ji);
7829 g_assert (!mono_class_is_gtd (method->klass));
7832 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7836 * mono_method_call_message_new:
7837 * @method: method to encapsulate
7838 * @params: parameters to the method
7839 * @invoke: optional, delegate invoke.
7840 * @cb: async callback delegate.
7841 * @state: state passed to the async callback.
7842 * @error: set on error.
7844 * Translates arguments pointers into a MonoMethodMessage.
7845 * On failure returns NULL and sets @error.
7848 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7849 MonoDelegate **cb, MonoObject **state, MonoError *error)
7851 MONO_REQ_GC_UNSAFE_MODE;
7853 mono_error_init (error);
7855 MonoDomain *domain = mono_domain_get ();
7856 MonoMethodSignature *sig = mono_method_signature (method);
7857 MonoMethodMessage *msg;
7860 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7861 return_val_if_nok (error, NULL);
7864 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7865 return_val_if_nok (error, NULL);
7866 mono_message_init (domain, msg, rm, NULL, error);
7867 return_val_if_nok (error, NULL);
7868 count = sig->param_count - 2;
7870 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7871 return_val_if_nok (error, NULL);
7872 mono_message_init (domain, msg, rm, NULL, error);
7873 return_val_if_nok (error, NULL);
7874 count = sig->param_count;
7877 for (i = 0; i < count; i++) {
7882 if (sig->params [i]->byref)
7883 vpos = *((gpointer *)params [i]);
7887 klass = mono_class_from_mono_type (sig->params [i]);
7889 if (klass->valuetype) {
7890 arg = mono_value_box_checked (domain, klass, vpos, error);
7891 return_val_if_nok (error, NULL);
7893 arg = *((MonoObject **)vpos);
7895 mono_array_setref (msg->args, i, arg);
7898 if (cb != NULL && state != NULL) {
7899 *cb = *((MonoDelegate **)params [i]);
7901 *state = *((MonoObject **)params [i]);
7908 * mono_method_return_message_restore:
7910 * Restore results from message based processing back to arguments pointers
7913 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7915 MONO_REQ_GC_UNSAFE_MODE;
7917 mono_error_init (error);
7919 MonoMethodSignature *sig = mono_method_signature (method);
7920 int i, j, type, size, out_len;
7922 if (out_args == NULL)
7924 out_len = mono_array_length (out_args);
7928 for (i = 0, j = 0; i < sig->param_count; i++) {
7929 MonoType *pt = sig->params [i];
7934 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7938 arg = (char *)mono_array_get (out_args, gpointer, j);
7941 g_assert (type != MONO_TYPE_VOID);
7943 if (MONO_TYPE_IS_REFERENCE (pt)) {
7944 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7947 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7948 size = mono_class_value_size (klass, NULL);
7949 if (klass->has_references)
7950 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7952 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7954 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7955 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7964 #ifndef DISABLE_REMOTING
7967 * mono_load_remote_field:
7968 * @this: pointer to an object
7969 * @klass: klass of the object containing @field
7970 * @field: the field to load
7971 * @res: a storage to store the result
7973 * This method is called by the runtime on attempts to load fields of
7974 * transparent proxy objects. @this points to such TP, @klass is the class of
7975 * the object containing @field. @res is a storage location which can be
7976 * used to store the result.
7978 * Returns: an address pointing to the value of field.
7981 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7984 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7985 mono_error_cleanup (&error);
7990 * mono_load_remote_field_checked:
7991 * @this: pointer to an object
7992 * @klass: klass of the object containing @field
7993 * @field: the field to load
7994 * @res: a storage to store the result
7995 * @error: set on error
7997 * This method is called by the runtime on attempts to load fields of
7998 * transparent proxy objects. @this points to such TP, @klass is the class of
7999 * the object containing @field. @res is a storage location which can be
8000 * used to store the result.
8002 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8005 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8007 MONO_REQ_GC_UNSAFE_MODE;
8009 static MonoMethod *getter = NULL;
8011 mono_error_init (error);
8013 MonoDomain *domain = mono_domain_get ();
8014 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8015 MonoClass *field_class;
8016 MonoMethodMessage *msg;
8017 MonoArray *out_args;
8021 g_assert (mono_object_is_transparent_proxy (this_obj));
8022 g_assert (res != NULL);
8024 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8025 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8030 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8032 mono_error_set_not_supported (error, "Linked away.");
8037 field_class = mono_class_from_mono_type (field->type);
8039 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8040 return_val_if_nok (error, NULL);
8041 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8042 return_val_if_nok (error, NULL);
8043 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8044 return_val_if_nok (error, NULL);
8045 mono_message_init (domain, msg, rm, out_args, error);
8046 return_val_if_nok (error, NULL);
8048 full_name = mono_type_get_full_name (klass);
8049 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8050 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8053 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8054 return_val_if_nok (error, NULL);
8057 mono_error_set_exception_instance (error, (MonoException *)exc);
8061 if (mono_array_length (out_args) == 0)
8064 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8066 if (field_class->valuetype) {
8067 return ((char *)*res) + sizeof (MonoObject);
8073 * mono_load_remote_field_new:
8078 * Missing documentation.
8081 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8085 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8086 mono_error_cleanup (&error);
8091 * mono_load_remote_field_new_checked:
8092 * @this: pointer to an object
8093 * @klass: klass of the object containing @field
8094 * @field: the field to load
8095 * @error: set on error.
8097 * This method is called by the runtime on attempts to load fields of
8098 * transparent proxy objects. @this points to such TP, @klass is the class of
8099 * the object containing @field.
8101 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8104 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8106 MONO_REQ_GC_UNSAFE_MODE;
8108 mono_error_init (error);
8110 static MonoMethod *tp_load = NULL;
8112 g_assert (mono_object_is_transparent_proxy (this_obj));
8115 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8117 mono_error_set_not_supported (error, "Linked away.");
8122 /* MonoType *type = mono_class_get_type (klass); */
8128 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8132 * mono_store_remote_field:
8133 * @this_obj: pointer to an object
8134 * @klass: klass of the object containing @field
8135 * @field: the field to load
8136 * @val: the value/object to store
8138 * This method is called by the runtime on attempts to store fields of
8139 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8140 * the object containing @field. @val is the new value to store in @field.
8143 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8146 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8147 mono_error_cleanup (&error);
8151 * mono_store_remote_field_checked:
8152 * @this_obj: pointer to an object
8153 * @klass: klass of the object containing @field
8154 * @field: the field to load
8155 * @val: the value/object to store
8156 * @error: set on error
8158 * This method is called by the runtime on attempts to store fields of
8159 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8160 * the object containing @field. @val is the new value to store in @field.
8162 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8165 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8168 MONO_REQ_GC_UNSAFE_MODE;
8170 mono_error_init (error);
8172 MonoDomain *domain = mono_domain_get ();
8173 MonoClass *field_class;
8176 g_assert (mono_object_is_transparent_proxy (this_obj));
8178 field_class = mono_class_from_mono_type (field->type);
8180 if (field_class->valuetype) {
8181 arg = mono_value_box_checked (domain, field_class, val, error);
8182 return_val_if_nok (error, FALSE);
8184 arg = *((MonoObject**)val);
8187 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8191 * mono_store_remote_field_new:
8197 * Missing documentation
8200 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8203 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8204 mono_error_cleanup (&error);
8208 * mono_store_remote_field_new_checked:
8215 * Missing documentation
8218 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8220 MONO_REQ_GC_UNSAFE_MODE;
8222 static MonoMethod *tp_store = NULL;
8224 mono_error_init (error);
8226 g_assert (mono_object_is_transparent_proxy (this_obj));
8229 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8231 mono_error_set_not_supported (error, "Linked away.");
8241 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8242 return is_ok (error);
8247 * mono_create_ftnptr:
8249 * Given a function address, create a function descriptor for it.
8250 * This is only needed on some platforms.
8253 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8255 return callbacks.create_ftnptr (domain, addr);
8259 * mono_get_addr_from_ftnptr:
8261 * Given a pointer to a function descriptor, return the function address.
8262 * This is only needed on some platforms.
8265 mono_get_addr_from_ftnptr (gpointer descr)
8267 return callbacks.get_addr_from_ftnptr (descr);
8271 * mono_string_chars:
8274 * Returns a pointer to the UCS16 characters stored in the MonoString
8277 mono_string_chars (MonoString *s)
8279 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8285 * mono_string_length:
8288 * Returns the lenght in characters of the string
8291 mono_string_length (MonoString *s)
8293 MONO_REQ_GC_UNSAFE_MODE;
8299 * mono_array_length:
8300 * @array: a MonoArray*
8302 * Returns the total number of elements in the array. This works for
8303 * both vectors and multidimensional arrays.
8306 mono_array_length (MonoArray *array)
8308 MONO_REQ_GC_UNSAFE_MODE;
8310 return array->max_length;
8314 * mono_array_addr_with_size:
8315 * @array: a MonoArray*
8316 * @size: size of the array elements
8317 * @idx: index into the array
8319 * Use this function to obtain the address for the @idx item on the
8320 * @array containing elements of size @size.
8322 * This method performs no bounds checking or type checking.
8324 * Returns the address of the @idx element in the array.
8327 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8329 MONO_REQ_GC_UNSAFE_MODE;
8331 return ((char*)(array)->vector) + size * idx;
8336 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8338 MonoDomain *domain = mono_domain_get ();
8342 mono_error_init (error);
8346 len = g_list_length (list);
8347 res = mono_array_new_checked (domain, eclass, len, error);
8348 return_val_if_nok (error, NULL);
8350 for (i = 0; list; list = list->next, i++)
8351 mono_array_set (res, gpointer, i, list->data);
8358 * The following section is purely to declare prototypes and
8359 * document the API, as these C files are processed by our
8365 * @array: array to alter
8366 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8367 * @index: index into the array
8368 * @value: value to set
8370 * Value Type version: This sets the @index's element of the @array
8371 * with elements of size sizeof(type) to the provided @value.
8373 * This macro does not attempt to perform type checking or bounds checking.
8375 * Use this to set value types in a `MonoArray`.
8377 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8382 * mono_array_setref:
8383 * @array: array to alter
8384 * @index: index into the array
8385 * @value: value to set
8387 * Reference Type version: This sets the @index's element of the
8388 * @array with elements of size sizeof(type) to the provided @value.
8390 * This macro does not attempt to perform type checking or bounds checking.
8392 * Use this to reference types in a `MonoArray`.
8394 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8400 * @array: array on which to operate on
8401 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8402 * @index: index into the array
8404 * Use this macro to retrieve the @index element of an @array and
8405 * extract the value assuming that the elements of the array match
8406 * the provided type value.
8408 * This method can be used with both arrays holding value types and
8409 * reference types. For reference types, the @type parameter should
8410 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8412 * This macro does not attempt to perform type checking or bounds checking.
8414 * Returns: The element at the @index position in the @array.
8416 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)