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;
79 * mono_runtime_object_init:
80 * @this_obj: the object to initialize
82 * This function calls the zero-argument constructor (which must
83 * exist) for the given object.
86 mono_runtime_object_init (MonoObject *this_obj)
89 mono_runtime_object_init_checked (this_obj, &error);
90 mono_error_assert_ok (&error);
94 * mono_runtime_object_init_checked:
95 * @this_obj: the object to initialize
96 * @error: set on error.
98 * This function calls the zero-argument constructor (which must
99 * exist) for the given object and returns TRUE on success, or FALSE
100 * on error and sets @error.
103 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
105 MONO_REQ_GC_UNSAFE_MODE;
107 MonoMethod *method = NULL;
108 MonoClass *klass = this_obj->vtable->klass;
110 mono_error_init (error);
111 method = mono_class_get_method_from_name (klass, ".ctor", 0);
113 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
115 if (method->klass->valuetype)
116 this_obj = (MonoObject *)mono_object_unbox (this_obj);
118 mono_runtime_invoke_checked (method, this_obj, NULL, error);
119 return is_ok (error);
122 /* The pseudo algorithm for type initialization from the spec
123 Note it doesn't say anything about domains - only threads.
125 2. If the type is initialized you are done.
126 2.1. If the type is not yet initialized, try to take an
128 2.2. If successful, record this thread as responsible for
129 initializing the type and proceed to step 2.3.
130 2.2.1. If not, see whether this thread or any thread
131 waiting for this thread to complete already holds the lock.
132 2.2.2. If so, return since blocking would create a deadlock. This thread
133 will now see an incompletely initialized state for the type,
134 but no deadlock will arise.
135 2.2.3 If not, block until the type is initialized then return.
136 2.3 Initialize the parent type and then all interfaces implemented
138 2.4 Execute the type initialization code for this type.
139 2.5 Mark the type as initialized, release the initialization lock,
140 awaken any threads waiting for this type to be initialized,
147 MonoNativeThreadId initializing_tid;
148 guint32 waiting_count;
150 MonoCoopMutex initialization_section;
151 } TypeInitializationLock;
153 /* for locking access to type_initialization_hash and blocked_thread_hash */
154 static MonoCoopMutex type_initialization_section;
157 mono_type_initialization_lock (void)
159 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
160 mono_coop_mutex_lock (&type_initialization_section);
164 mono_type_initialization_unlock (void)
166 mono_coop_mutex_unlock (&type_initialization_section);
170 mono_type_init_lock (TypeInitializationLock *lock)
172 MONO_REQ_GC_NEUTRAL_MODE;
174 mono_coop_mutex_lock (&lock->initialization_section);
178 mono_type_init_unlock (TypeInitializationLock *lock)
180 mono_coop_mutex_unlock (&lock->initialization_section);
183 /* from vtable to lock */
184 static GHashTable *type_initialization_hash;
186 /* from thread id to thread id being waited on */
187 static GHashTable *blocked_thread_hash;
190 static MonoThread *main_thread;
192 /* Functions supplied by the runtime */
193 static MonoRuntimeCallbacks callbacks;
196 * mono_thread_set_main:
197 * @thread: thread to set as the main thread
199 * This function can be used to instruct the runtime to treat @thread
200 * as the main thread, ie, the thread that would normally execute the Main()
201 * method. This basically means that at the end of @thread, the runtime will
202 * wait for the existing foreground threads to quit and other such details.
205 mono_thread_set_main (MonoThread *thread)
207 MONO_REQ_GC_UNSAFE_MODE;
209 static gboolean registered = FALSE;
212 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
216 main_thread = thread;
220 mono_thread_get_main (void)
222 MONO_REQ_GC_UNSAFE_MODE;
228 mono_type_initialization_init (void)
230 mono_coop_mutex_init_recursive (&type_initialization_section);
231 type_initialization_hash = g_hash_table_new (NULL, NULL);
232 blocked_thread_hash = g_hash_table_new (NULL, NULL);
233 mono_os_mutex_init_recursive (&ldstr_section);
237 mono_type_initialization_cleanup (void)
240 /* This is causing race conditions with
241 * mono_release_type_locks
243 mono_coop_mutex_destroy (&type_initialization_section);
244 g_hash_table_destroy (type_initialization_hash);
245 type_initialization_hash = NULL;
247 mono_os_mutex_destroy (&ldstr_section);
248 g_hash_table_destroy (blocked_thread_hash);
249 blocked_thread_hash = NULL;
255 * get_type_init_exception_for_vtable:
257 * Return the stored type initialization exception for VTABLE.
259 static MonoException*
260 get_type_init_exception_for_vtable (MonoVTable *vtable)
262 MONO_REQ_GC_UNSAFE_MODE;
265 MonoDomain *domain = vtable->domain;
266 MonoClass *klass = vtable->klass;
270 if (!vtable->init_failed)
271 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
274 * If the initializing thread was rudely aborted, the exception is not stored
278 mono_domain_lock (domain);
279 if (domain->type_init_exception_hash)
280 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
281 mono_domain_unlock (domain);
284 if (klass->name_space && *klass->name_space)
285 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
287 full_name = g_strdup (klass->name);
288 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
290 return_val_if_nok (&error, NULL);
297 * mono_runtime_class_init:
298 * @vtable: vtable that needs to be initialized
300 * This routine calls the class constructor for @vtable.
303 mono_runtime_class_init (MonoVTable *vtable)
305 MONO_REQ_GC_UNSAFE_MODE;
308 mono_runtime_class_init_full (vtable, &error);
309 mono_error_assert_ok (&error);
313 * mono_runtime_class_init_full:
314 * @vtable that neeeds to be initialized
315 * @error set on error
317 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
321 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
323 MONO_REQ_GC_UNSAFE_MODE;
325 MonoMethod *method = NULL;
328 MonoDomain *domain = vtable->domain;
329 TypeInitializationLock *lock;
330 MonoNativeThreadId tid;
331 int do_initialization = 0;
332 MonoDomain *last_domain = NULL;
333 MonoException * pending_tae = NULL;
335 mono_error_init (error);
337 if (vtable->initialized)
340 klass = vtable->klass;
342 if (!klass->image->checked_module_cctor) {
343 mono_image_check_for_module_cctor (klass->image);
344 if (klass->image->has_module_cctor) {
345 MonoClass *module_klass;
346 MonoVTable *module_vtable;
348 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
353 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
356 if (!mono_runtime_class_init_full (module_vtable, error))
360 method = mono_class_get_cctor (klass);
362 vtable->initialized = 1;
366 tid = mono_native_thread_id_get ();
368 mono_type_initialization_lock ();
369 /* double check... */
370 if (vtable->initialized) {
371 mono_type_initialization_unlock ();
374 if (vtable->init_failed) {
375 mono_type_initialization_unlock ();
377 /* The type initialization already failed once, rethrow the same exception */
378 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
381 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
383 /* This thread will get to do the initialization */
384 if (mono_domain_get () != domain) {
385 /* Transfer into the target domain */
386 last_domain = mono_domain_get ();
387 if (!mono_domain_set (domain, FALSE)) {
388 vtable->initialized = 1;
389 mono_type_initialization_unlock ();
390 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
394 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
395 mono_coop_mutex_init_recursive (&lock->initialization_section);
396 lock->initializing_tid = tid;
397 lock->waiting_count = 1;
399 /* grab the vtable lock while this thread still owns type_initialization_section */
400 /* This is why type_initialization_lock needs to enter blocking mode */
401 mono_type_init_lock (lock);
402 g_hash_table_insert (type_initialization_hash, vtable, lock);
403 do_initialization = 1;
406 TypeInitializationLock *pending_lock;
408 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
409 mono_type_initialization_unlock ();
412 /* see if the thread doing the initialization is already blocked on this thread */
413 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
414 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
415 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
416 if (!pending_lock->done) {
417 mono_type_initialization_unlock ();
420 /* the thread doing the initialization is blocked on this thread,
421 but on a lock that has already been freed. It just hasn't got
426 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
428 ++lock->waiting_count;
429 /* record the fact that we are waiting on the initializing thread */
430 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
432 mono_type_initialization_unlock ();
434 if (do_initialization) {
435 MonoException *exc = NULL;
437 mono_threads_begin_abort_protected_block ();
438 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
439 mono_threads_end_abort_protected_block ();
441 //exception extracted, error will be set to the right value later
442 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
443 exc = mono_error_convert_to_exception (error);
445 mono_error_cleanup (error);
447 mono_error_init (error);
449 /* If the initialization failed, mark the class as unusable. */
450 /* Avoid infinite loops */
452 (klass->image == mono_defaults.corlib &&
453 !strcmp (klass->name_space, "System") &&
454 !strcmp (klass->name, "TypeInitializationException")))) {
455 vtable->init_failed = 1;
457 if (klass->name_space && *klass->name_space)
458 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
460 full_name = g_strdup (klass->name);
462 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
465 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
468 * Store the exception object so it could be thrown on subsequent
471 mono_domain_lock (domain);
472 if (!domain->type_init_exception_hash)
473 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");
474 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
475 mono_domain_unlock (domain);
479 mono_domain_set (last_domain, TRUE);
481 mono_type_init_unlock (lock);
482 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
484 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
486 pending_tae = mono_thread_try_resume_interruption ();
488 /* this just blocks until the initializing thread is done */
489 mono_type_init_lock (lock);
490 mono_type_init_unlock (lock);
493 mono_type_initialization_lock ();
494 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
495 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
496 --lock->waiting_count;
497 if (lock->waiting_count == 0) {
498 mono_coop_mutex_destroy (&lock->initialization_section);
499 g_hash_table_remove (type_initialization_hash, vtable);
502 mono_memory_barrier ();
503 if (!vtable->init_failed)
504 vtable->initialized = 1;
505 mono_type_initialization_unlock ();
509 mono_error_set_exception_instance (error, pending_tae);
510 else if (vtable->init_failed) {
511 /* Either we were the initializing thread or we waited for the initialization */
512 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
519 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
521 MONO_REQ_GC_NEUTRAL_MODE;
523 MonoVTable *vtable = (MonoVTable*)key;
525 TypeInitializationLock *lock = (TypeInitializationLock*) value;
526 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
529 * Have to set this since it cannot be set by the normal code in
530 * mono_runtime_class_init (). In this case, the exception object is not stored,
531 * and get_type_init_exception_for_class () needs to be aware of this.
533 vtable->init_failed = 1;
534 mono_type_init_unlock (lock);
535 --lock->waiting_count;
536 if (lock->waiting_count == 0) {
537 mono_coop_mutex_destroy (&lock->initialization_section);
546 mono_release_type_locks (MonoInternalThread *thread)
548 MONO_REQ_GC_UNSAFE_MODE;
550 mono_type_initialization_lock ();
551 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
552 mono_type_initialization_unlock ();
555 #ifndef DISABLE_REMOTING
558 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
560 if (!callbacks.create_remoting_trampoline)
561 g_error ("remoting not installed");
562 return callbacks.create_remoting_trampoline (domain, method, target, error);
567 static MonoImtTrampolineBuilder imt_trampoline_builder;
568 static gboolean always_build_imt_trampolines;
570 #if (MONO_IMT_SIZE > 32)
571 #error "MONO_IMT_SIZE cannot be larger than 32"
575 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
577 memcpy (&callbacks, cbs, sizeof (*cbs));
580 MonoRuntimeCallbacks*
581 mono_get_runtime_callbacks (void)
587 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
589 imt_trampoline_builder = func;
593 mono_set_always_build_imt_trampolines (gboolean value)
595 always_build_imt_trampolines = value;
599 * mono_compile_method:
600 * @method: The method to compile.
602 * This JIT-compiles the method, and returns the pointer to the native code
606 mono_compile_method (MonoMethod *method)
609 gpointer result = mono_compile_method_checked (method, &error);
610 mono_error_cleanup (&error);
615 * mono_compile_method:
616 * @method: The method to compile.
617 * @error: set on error.
619 * This JIT-compiles the method, and returns the pointer to the native code
620 * produced. On failure returns NULL and sets @error.
623 mono_compile_method_checked (MonoMethod *method, MonoError *error)
627 MONO_REQ_GC_NEUTRAL_MODE
629 mono_error_init (error);
631 g_assert (callbacks.compile_method);
632 res = callbacks.compile_method (method, error);
637 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
641 MONO_REQ_GC_NEUTRAL_MODE;
643 mono_error_init (error);
644 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
649 mono_runtime_create_delegate_trampoline (MonoClass *klass)
651 MONO_REQ_GC_NEUTRAL_MODE
653 g_assert (callbacks.create_delegate_trampoline);
654 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
658 * mono_runtime_free_method:
659 * @domain; domain where the method is hosted
660 * @method: method to release
662 * This routine is invoked to free the resources associated with
663 * a method that has been JIT compiled. This is used to discard
664 * methods that were used only temporarily (for example, used in marshalling)
668 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
670 MONO_REQ_GC_NEUTRAL_MODE
672 if (callbacks.free_method)
673 callbacks.free_method (domain, method);
675 mono_method_clear_object (domain, method);
677 mono_free_method (method);
681 * The vtables in the root appdomain are assumed to be reachable by other
682 * roots, and we don't use typed allocation in the other domains.
685 /* The sync block is no longer a GC pointer */
686 #define GC_HEADER_BITMAP (0)
688 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
691 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
693 MONO_REQ_GC_NEUTRAL_MODE;
695 MonoClassField *field;
701 max_size = mono_class_data_size (klass) / sizeof (gpointer);
703 max_size = klass->instance_size / sizeof (gpointer);
704 if (max_size > size) {
705 g_assert (offset <= 0);
706 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
711 /*An Ephemeron cannot be marked by sgen*/
712 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
714 memset (bitmap, 0, size / 8);
719 for (p = klass; p != NULL; p = p->parent) {
720 gpointer iter = NULL;
721 while ((field = mono_class_get_fields (p, &iter))) {
725 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
727 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
730 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
733 /* FIXME: should not happen, flag as type load error */
734 if (field->type->byref)
737 if (static_fields && field->offset == -1)
741 pos = field->offset / sizeof (gpointer);
744 type = mono_type_get_underlying_type (field->type);
745 switch (type->type) {
748 case MONO_TYPE_FNPTR:
750 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
755 if (klass->image != mono_defaults.corlib)
758 case MONO_TYPE_STRING:
759 case MONO_TYPE_SZARRAY:
760 case MONO_TYPE_CLASS:
761 case MONO_TYPE_OBJECT:
762 case MONO_TYPE_ARRAY:
763 g_assert ((field->offset % sizeof(gpointer)) == 0);
765 g_assert (pos < size || pos <= max_size);
766 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
767 *max_set = MAX (*max_set, pos);
769 case MONO_TYPE_GENERICINST:
770 if (!mono_type_generic_inst_is_valuetype (type)) {
771 g_assert ((field->offset % sizeof(gpointer)) == 0);
773 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
774 *max_set = MAX (*max_set, pos);
779 case MONO_TYPE_VALUETYPE: {
780 MonoClass *fclass = mono_class_from_mono_type (field->type);
781 if (fclass->has_references) {
782 /* remove the object header */
783 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
797 case MONO_TYPE_BOOLEAN:
801 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
812 * mono_class_compute_bitmap:
814 * Mono internal function to compute a bitmap of reference fields in a class.
817 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
819 MONO_REQ_GC_NEUTRAL_MODE;
821 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
826 * similar to the above, but sets the bits in the bitmap for any non-ref field
827 * and ignores static fields
830 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
832 MonoClassField *field;
837 max_size = class->instance_size / sizeof (gpointer);
838 if (max_size >= size) {
839 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
842 for (p = class; p != NULL; p = p->parent) {
843 gpointer iter = NULL;
844 while ((field = mono_class_get_fields (p, &iter))) {
847 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
849 /* FIXME: should not happen, flag as type load error */
850 if (field->type->byref)
853 pos = field->offset / sizeof (gpointer);
856 type = mono_type_get_underlying_type (field->type);
857 switch (type->type) {
858 #if SIZEOF_VOID_P == 8
862 case MONO_TYPE_FNPTR:
867 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
868 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
869 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
872 #if SIZEOF_VOID_P == 4
876 case MONO_TYPE_FNPTR:
881 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
882 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
883 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
889 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
890 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
891 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
894 case MONO_TYPE_BOOLEAN:
897 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
899 case MONO_TYPE_STRING:
900 case MONO_TYPE_SZARRAY:
901 case MONO_TYPE_CLASS:
902 case MONO_TYPE_OBJECT:
903 case MONO_TYPE_ARRAY:
905 case MONO_TYPE_GENERICINST:
906 if (!mono_type_generic_inst_is_valuetype (type)) {
911 case MONO_TYPE_VALUETYPE: {
912 MonoClass *fclass = mono_class_from_mono_type (field->type);
913 /* remove the object header */
914 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
918 g_assert_not_reached ();
927 * mono_class_insecure_overlapping:
928 * check if a class with explicit layout has references and non-references
929 * fields overlapping.
931 * Returns: TRUE if it is insecure to load the type.
934 mono_class_insecure_overlapping (MonoClass *klass)
938 gsize default_bitmap [4] = {0};
940 gsize default_nrbitmap [4] = {0};
941 int i, insecure = FALSE;
944 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
945 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
947 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
948 int idx = i % (sizeof (bitmap [0]) * 8);
949 if (bitmap [idx] & nrbitmap [idx]) {
954 if (bitmap != default_bitmap)
956 if (nrbitmap != default_nrbitmap)
959 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
967 ves_icall_string_alloc (int length)
970 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
971 mono_error_set_pending_exception (&error);
977 mono_class_compute_gc_descriptor (MonoClass *klass)
979 MONO_REQ_GC_NEUTRAL_MODE;
983 gsize default_bitmap [4] = {0};
984 static gboolean gcj_inited = FALSE;
989 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
990 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
993 mono_loader_unlock ();
997 mono_class_init (klass);
999 if (klass->gc_descr_inited)
1002 klass->gc_descr_inited = TRUE;
1003 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1005 bitmap = default_bitmap;
1006 if (klass == mono_defaults.string_class) {
1007 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1008 } else if (klass->rank) {
1009 mono_class_compute_gc_descriptor (klass->element_class);
1010 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1012 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1013 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1014 class->name_space, class->name);*/
1016 /* remove the object header */
1017 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1018 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));
1019 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1020 class->name_space, class->name);*/
1021 if (bitmap != default_bitmap)
1025 /*static int count = 0;
1028 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1029 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1031 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1032 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1034 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1035 if (bitmap != default_bitmap)
1041 * field_is_special_static:
1042 * @fklass: The MonoClass to look up.
1043 * @field: The MonoClassField describing the field.
1045 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1046 * SPECIAL_STATIC_NONE otherwise.
1049 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1051 MONO_REQ_GC_NEUTRAL_MODE;
1054 MonoCustomAttrInfo *ainfo;
1056 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1057 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1060 for (i = 0; i < ainfo->num_attrs; ++i) {
1061 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1062 if (klass->image == mono_defaults.corlib) {
1063 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1064 mono_custom_attrs_free (ainfo);
1065 return SPECIAL_STATIC_THREAD;
1067 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1068 mono_custom_attrs_free (ainfo);
1069 return SPECIAL_STATIC_CONTEXT;
1073 mono_custom_attrs_free (ainfo);
1074 return SPECIAL_STATIC_NONE;
1077 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1078 #define mix(a,b,c) { \
1079 a -= c; a ^= rot(c, 4); c += b; \
1080 b -= a; b ^= rot(a, 6); a += c; \
1081 c -= b; c ^= rot(b, 8); b += a; \
1082 a -= c; a ^= rot(c,16); c += b; \
1083 b -= a; b ^= rot(a,19); a += c; \
1084 c -= b; c ^= rot(b, 4); b += a; \
1086 #define final(a,b,c) { \
1087 c ^= b; c -= rot(b,14); \
1088 a ^= c; a -= rot(c,11); \
1089 b ^= a; b -= rot(a,25); \
1090 c ^= b; c -= rot(b,16); \
1091 a ^= c; a -= rot(c,4); \
1092 b ^= a; b -= rot(a,14); \
1093 c ^= b; c -= rot(b,24); \
1097 * mono_method_get_imt_slot:
1099 * The IMT slot is embedded into AOTed code, so this must return the same value
1100 * for the same method across all executions. This means:
1101 * - pointers shouldn't be used as hash values.
1102 * - mono_metadata_str_hash () should be used for hashing strings.
1105 mono_method_get_imt_slot (MonoMethod *method)
1107 MONO_REQ_GC_NEUTRAL_MODE;
1109 MonoMethodSignature *sig;
1111 guint32 *hashes_start, *hashes;
1115 /* This can be used to stress tests the collision code */
1119 * We do this to simplify generic sharing. It will hurt
1120 * performance in cases where a class implements two different
1121 * instantiations of the same generic interface.
1122 * The code in build_imt_slots () depends on this.
1124 if (method->is_inflated)
1125 method = ((MonoMethodInflated*)method)->declaring;
1127 sig = mono_method_signature (method);
1128 hashes_count = sig->param_count + 4;
1129 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1130 hashes = hashes_start;
1132 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1133 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1134 method->klass->name_space, method->klass->name, method->name);
1137 /* Initialize hashes */
1138 hashes [0] = mono_metadata_str_hash (method->klass->name);
1139 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1140 hashes [2] = mono_metadata_str_hash (method->name);
1141 hashes [3] = mono_metadata_type_hash (sig->ret);
1142 for (i = 0; i < sig->param_count; i++) {
1143 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1146 /* Setup internal state */
1147 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1149 /* Handle most of the hashes */
1150 while (hashes_count > 3) {
1159 /* Handle the last 3 hashes (all the case statements fall through) */
1160 switch (hashes_count) {
1161 case 3 : c += hashes [2];
1162 case 2 : b += hashes [1];
1163 case 1 : a += hashes [0];
1165 case 0: /* nothing left to add */
1169 g_free (hashes_start);
1170 /* Report the result */
1171 return c % MONO_IMT_SIZE;
1180 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1181 MONO_REQ_GC_NEUTRAL_MODE;
1183 guint32 imt_slot = mono_method_get_imt_slot (method);
1184 MonoImtBuilderEntry *entry;
1186 if (slot_num >= 0 && imt_slot != slot_num) {
1187 /* we build just a single imt slot and this is not it */
1191 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1192 entry->key = method;
1193 entry->value.vtable_slot = vtable_slot;
1194 entry->next = imt_builder [imt_slot];
1195 if (imt_builder [imt_slot] != NULL) {
1196 entry->children = imt_builder [imt_slot]->children + 1;
1197 if (entry->children == 1) {
1198 mono_stats.imt_slots_with_collisions++;
1199 *imt_collisions_bitmap |= (1 << imt_slot);
1202 entry->children = 0;
1203 mono_stats.imt_used_slots++;
1205 imt_builder [imt_slot] = entry;
1208 char *method_name = mono_method_full_name (method, TRUE);
1209 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1210 method, method_name, imt_slot, vtable_slot, entry->children);
1211 g_free (method_name);
1218 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1220 MonoMethod *method = e->key;
1221 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1225 method->klass->name_space,
1226 method->klass->name,
1229 printf (" * %s: NULL\n", message);
1235 compare_imt_builder_entries (const void *p1, const void *p2) {
1236 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1237 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1239 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1243 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1245 MONO_REQ_GC_NEUTRAL_MODE;
1247 int count = end - start;
1248 int chunk_start = out_array->len;
1251 for (i = start; i < end; ++i) {
1252 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1253 item->key = sorted_array [i]->key;
1254 item->value = sorted_array [i]->value;
1255 item->has_target_code = sorted_array [i]->has_target_code;
1256 item->is_equals = TRUE;
1258 item->check_target_idx = out_array->len + 1;
1260 item->check_target_idx = 0;
1261 g_ptr_array_add (out_array, item);
1264 int middle = start + count / 2;
1265 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1267 item->key = sorted_array [middle]->key;
1268 item->is_equals = FALSE;
1269 g_ptr_array_add (out_array, item);
1270 imt_emit_ir (sorted_array, start, middle, out_array);
1271 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1277 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1278 MONO_REQ_GC_NEUTRAL_MODE;
1280 int number_of_entries = entries->children + 1;
1281 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1282 GPtrArray *result = g_ptr_array_new ();
1283 MonoImtBuilderEntry *current_entry;
1286 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1287 sorted_array [i] = current_entry;
1289 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1291 /*for (i = 0; i < number_of_entries; i++) {
1292 print_imt_entry (" sorted array:", sorted_array [i], i);
1295 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1297 g_free (sorted_array);
1302 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1304 MONO_REQ_GC_NEUTRAL_MODE;
1306 if (imt_builder_entry != NULL) {
1307 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1308 /* No collision, return the vtable slot contents */
1309 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1311 /* Collision, build the trampoline */
1312 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1315 result = imt_trampoline_builder (vtable, domain,
1316 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1317 for (i = 0; i < imt_ir->len; ++i)
1318 g_free (g_ptr_array_index (imt_ir, i));
1319 g_ptr_array_free (imt_ir, TRUE);
1331 static MonoImtBuilderEntry*
1332 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1335 * LOCKING: requires the loader and domain locks.
1339 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1341 MONO_REQ_GC_NEUTRAL_MODE;
1345 guint32 imt_collisions_bitmap = 0;
1346 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1347 int method_count = 0;
1348 gboolean record_method_count_for_max_collisions = FALSE;
1349 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1352 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1354 for (i = 0; i < klass->interface_offsets_count; ++i) {
1355 MonoClass *iface = klass->interfaces_packed [i];
1356 int interface_offset = klass->interface_offsets_packed [i];
1357 int method_slot_in_interface, vt_slot;
1359 if (mono_class_has_variant_generic_params (iface))
1360 has_variant_iface = TRUE;
1362 mono_class_setup_methods (iface);
1363 vt_slot = interface_offset;
1364 int mcount = mono_class_get_method_count (iface);
1365 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1368 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1370 * The imt slot of the method is the same as for its declaring method,
1371 * see the comment in mono_method_get_imt_slot (), so we can
1372 * avoid inflating methods which will be discarded by
1373 * add_imt_builder_entry anyway.
1375 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1376 if (mono_method_get_imt_slot (method) != slot_num) {
1381 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1382 if (method->is_generic) {
1383 has_generic_virtual = TRUE;
1388 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1389 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1394 if (extra_interfaces) {
1395 int interface_offset = klass->vtable_size;
1397 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1398 MonoClass* iface = (MonoClass *)list_item->data;
1399 int method_slot_in_interface;
1400 int mcount = mono_class_get_method_count (iface);
1401 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1402 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1404 if (method->is_generic)
1405 has_generic_virtual = TRUE;
1406 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1408 interface_offset += mcount;
1411 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1412 /* overwrite the imt slot only if we're building all the entries or if
1413 * we're building this specific one
1415 if (slot_num < 0 || i == slot_num) {
1416 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1419 if (imt_builder [i]) {
1420 MonoImtBuilderEntry *entry;
1422 /* Link entries with imt_builder [i] */
1423 for (entry = entries; entry->next; entry = entry->next) {
1425 MonoMethod *method = (MonoMethod*)entry->key;
1426 char *method_name = mono_method_full_name (method, TRUE);
1427 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1428 g_free (method_name);
1431 entry->next = imt_builder [i];
1432 entries->children += imt_builder [i]->children + 1;
1434 imt_builder [i] = entries;
1437 if (has_generic_virtual || has_variant_iface) {
1439 * There might be collisions later when the the trampoline is expanded.
1441 imt_collisions_bitmap |= (1 << i);
1444 * The IMT trampoline might be called with an instance of one of the
1445 * generic virtual methods, so has to fallback to the IMT trampoline.
1447 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1449 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1452 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1456 if (imt_builder [i] != NULL) {
1457 int methods_in_slot = imt_builder [i]->children + 1;
1458 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1459 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1460 record_method_count_for_max_collisions = TRUE;
1462 method_count += methods_in_slot;
1466 mono_stats.imt_number_of_methods += method_count;
1467 if (record_method_count_for_max_collisions) {
1468 mono_stats.imt_method_count_when_max_collisions = method_count;
1471 for (i = 0; i < MONO_IMT_SIZE; i++) {
1472 MonoImtBuilderEntry* entry = imt_builder [i];
1473 while (entry != NULL) {
1474 MonoImtBuilderEntry* next = entry->next;
1479 g_free (imt_builder);
1480 /* we OR the bitmap since we may build just a single imt slot at a time */
1481 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1485 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1486 MONO_REQ_GC_NEUTRAL_MODE;
1488 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1492 * mono_vtable_build_imt_slot:
1493 * @vtable: virtual object table struct
1494 * @imt_slot: slot in the IMT table
1496 * Fill the given @imt_slot in the IMT table of @vtable with
1497 * a trampoline or a trampoline for the case of collisions.
1498 * This is part of the internal mono API.
1500 * LOCKING: Take the domain lock.
1503 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1505 MONO_REQ_GC_NEUTRAL_MODE;
1507 gpointer *imt = (gpointer*)vtable;
1508 imt -= MONO_IMT_SIZE;
1509 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1511 /* no support for extra interfaces: the proxy objects will need
1512 * to build the complete IMT
1513 * Update and heck needs to ahppen inside the proper domain lock, as all
1514 * the changes made to a MonoVTable.
1516 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1517 mono_domain_lock (vtable->domain);
1518 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1519 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1520 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1521 mono_domain_unlock (vtable->domain);
1522 mono_loader_unlock ();
1525 #define THUNK_THRESHOLD 10
1528 * mono_method_alloc_generic_virtual_trampoline:
1530 * @size: size in bytes
1532 * Allocs size bytes to be used for the code of a generic virtual
1533 * trampoline. It's either allocated from the domain's code manager or
1534 * reused from a previously invalidated piece.
1536 * LOCKING: The domain lock must be held.
1539 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1541 MONO_REQ_GC_NEUTRAL_MODE;
1543 static gboolean inited = FALSE;
1544 static int generic_virtual_trampolines_size = 0;
1547 mono_counters_register ("Generic virtual trampoline bytes",
1548 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1551 generic_virtual_trampolines_size += size;
1553 return mono_domain_code_reserve (domain, size);
1556 typedef struct _GenericVirtualCase {
1560 struct _GenericVirtualCase *next;
1561 } GenericVirtualCase;
1564 * get_generic_virtual_entries:
1566 * Return IMT entries for the generic virtual method instances and
1567 * variant interface methods for vtable slot
1570 static MonoImtBuilderEntry*
1571 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1573 MONO_REQ_GC_NEUTRAL_MODE;
1575 GenericVirtualCase *list;
1576 MonoImtBuilderEntry *entries;
1578 mono_domain_lock (domain);
1579 if (!domain->generic_virtual_cases)
1580 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1582 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1585 for (; list; list = list->next) {
1586 MonoImtBuilderEntry *entry;
1588 if (list->count < THUNK_THRESHOLD)
1591 entry = g_new0 (MonoImtBuilderEntry, 1);
1592 entry->key = list->method;
1593 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1594 entry->has_target_code = 1;
1596 entry->children = entries->children + 1;
1597 entry->next = entries;
1601 mono_domain_unlock (domain);
1603 /* FIXME: Leaking memory ? */
1608 * mono_method_add_generic_virtual_invocation:
1610 * @vtable_slot: pointer to the vtable slot
1611 * @method: the inflated generic virtual method
1612 * @code: the method's code
1614 * Registers a call via unmanaged code to a generic virtual method
1615 * instantiation or variant interface method. If the number of calls reaches a threshold
1616 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1617 * virtual method trampoline.
1620 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1621 gpointer *vtable_slot,
1622 MonoMethod *method, gpointer code)
1624 MONO_REQ_GC_NEUTRAL_MODE;
1626 static gboolean inited = FALSE;
1627 static int num_added = 0;
1628 static int num_freed = 0;
1630 GenericVirtualCase *gvc, *list;
1631 MonoImtBuilderEntry *entries;
1635 mono_domain_lock (domain);
1636 if (!domain->generic_virtual_cases)
1637 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1640 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1641 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1645 /* Check whether the case was already added */
1646 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1649 if (gvc->method == method)
1654 /* If not found, make a new one */
1656 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1657 gvc->method = method;
1660 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1662 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1667 if (++gvc->count == THUNK_THRESHOLD) {
1668 gpointer *old_thunk = (void **)*vtable_slot;
1669 gpointer vtable_trampoline = NULL;
1670 gpointer imt_trampoline = NULL;
1672 if ((gpointer)vtable_slot < (gpointer)vtable) {
1673 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1674 int imt_slot = MONO_IMT_SIZE + displacement;
1676 /* Force the rebuild of the trampoline at the next call */
1677 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1678 *vtable_slot = imt_trampoline;
1680 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1682 entries = get_generic_virtual_entries (domain, vtable_slot);
1684 sorted = imt_sort_slot_entries (entries);
1686 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1690 MonoImtBuilderEntry *next = entries->next;
1695 for (i = 0; i < sorted->len; ++i)
1696 g_free (g_ptr_array_index (sorted, i));
1697 g_ptr_array_free (sorted, TRUE);
1699 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1704 mono_domain_unlock (domain);
1707 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1710 * mono_class_vtable:
1711 * @domain: the application domain
1712 * @class: the class to initialize
1714 * VTables are domain specific because we create domain specific code, and
1715 * they contain the domain specific static class data.
1716 * On failure, NULL is returned, and class->exception_type is set.
1719 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1722 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1723 mono_error_cleanup (&error);
1728 * mono_class_vtable_full:
1729 * @domain: the application domain
1730 * @class: the class to initialize
1731 * @error set on failure.
1733 * VTables are domain specific because we create domain specific code, and
1734 * they contain the domain specific static class data.
1737 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1739 MONO_REQ_GC_UNSAFE_MODE;
1741 MonoClassRuntimeInfo *runtime_info;
1743 mono_error_init (error);
1747 if (mono_class_has_failure (klass)) {
1748 mono_error_set_for_class_failure (error, klass);
1752 /* this check can be inlined in jitted code, too */
1753 runtime_info = klass->runtime_info;
1754 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1755 return runtime_info->domain_vtables [domain->domain_id];
1756 return mono_class_create_runtime_vtable (domain, klass, error);
1760 * mono_class_try_get_vtable:
1761 * @domain: the application domain
1762 * @class: the class to initialize
1764 * This function tries to get the associated vtable from @class if
1765 * it was already created.
1768 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1770 MONO_REQ_GC_NEUTRAL_MODE;
1772 MonoClassRuntimeInfo *runtime_info;
1776 runtime_info = klass->runtime_info;
1777 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1778 return runtime_info->domain_vtables [domain->domain_id];
1783 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1785 MONO_REQ_GC_NEUTRAL_MODE;
1787 size_t alloc_offset;
1790 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1791 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1792 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1794 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1795 g_assert ((imt_table_bytes & 7) == 4);
1802 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1806 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1808 MONO_REQ_GC_UNSAFE_MODE;
1811 MonoClassRuntimeInfo *runtime_info, *old_info;
1812 MonoClassField *field;
1814 int i, vtable_slots;
1815 size_t imt_table_bytes;
1817 guint32 vtable_size, class_size;
1819 gpointer *interface_offsets;
1821 mono_error_init (error);
1823 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1824 mono_domain_lock (domain);
1825 runtime_info = klass->runtime_info;
1826 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1827 mono_domain_unlock (domain);
1828 mono_loader_unlock ();
1829 return runtime_info->domain_vtables [domain->domain_id];
1831 if (!klass->inited || mono_class_has_failure (klass)) {
1832 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1833 mono_domain_unlock (domain);
1834 mono_loader_unlock ();
1835 mono_error_set_for_class_failure (error, klass);
1840 /* Array types require that their element type be valid*/
1841 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1842 MonoClass *element_class = klass->element_class;
1843 if (!element_class->inited)
1844 mono_class_init (element_class);
1846 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1847 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1848 mono_class_setup_vtable (element_class);
1850 if (mono_class_has_failure (element_class)) {
1851 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1852 if (!mono_class_has_failure (klass))
1853 mono_class_set_type_load_failure (klass, "");
1854 mono_domain_unlock (domain);
1855 mono_loader_unlock ();
1856 mono_error_set_for_class_failure (error, klass);
1862 * For some classes, mono_class_init () already computed klass->vtable_size, and
1863 * that is all that is needed because of the vtable trampolines.
1865 if (!klass->vtable_size)
1866 mono_class_setup_vtable (klass);
1868 if (mono_class_is_ginst (klass) && !klass->vtable)
1869 mono_class_check_vtable_constraints (klass, NULL);
1871 /* Initialize klass->has_finalize */
1872 mono_class_has_finalizer (klass);
1874 if (mono_class_has_failure (klass)) {
1875 mono_domain_unlock (domain);
1876 mono_loader_unlock ();
1877 mono_error_set_for_class_failure (error, klass);
1881 vtable_slots = klass->vtable_size;
1882 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1883 class_size = mono_class_data_size (klass);
1887 if (klass->interface_offsets_count) {
1888 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1889 mono_stats.imt_number_of_tables++;
1890 mono_stats.imt_tables_size += imt_table_bytes;
1892 imt_table_bytes = 0;
1895 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1897 mono_stats.used_class_count++;
1898 mono_stats.class_vtable_size += vtable_size;
1900 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1901 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1902 g_assert (!((gsize)vt & 7));
1905 vt->rank = klass->rank;
1906 vt->domain = domain;
1908 mono_class_compute_gc_descriptor (klass);
1910 * We can't use typed allocation in the non-root domains, since the
1911 * collector needs the GC descriptor stored in the vtable even after
1912 * the mempool containing the vtable is destroyed when the domain is
1913 * unloaded. An alternative might be to allocate vtables in the GC
1914 * heap, but this does not seem to work (it leads to crashes inside
1915 * libgc). If that approach is tried, two gc descriptors need to be
1916 * allocated for each class: one for the root domain, and one for all
1917 * other domains. The second descriptor should contain a bit for the
1918 * vtable field in MonoObject, since we can no longer assume the
1919 * vtable is reachable by other roots after the appdomain is unloaded.
1921 #ifdef HAVE_BOEHM_GC
1922 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1923 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1926 vt->gc_descr = klass->gc_descr;
1928 gc_bits = mono_gc_get_vtable_bits (klass);
1929 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1931 vt->gc_bits = gc_bits;
1934 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1935 if (klass->has_static_refs) {
1936 MonoGCDescriptor statics_gc_descr;
1938 gsize default_bitmap [4] = {0};
1941 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1942 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1943 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1944 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1945 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1946 if (bitmap != default_bitmap)
1949 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1951 vt->has_static_fields = TRUE;
1952 mono_stats.class_static_data_size += class_size;
1956 while ((field = mono_class_get_fields (klass, &iter))) {
1957 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1959 if (mono_field_is_deleted (field))
1961 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1962 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1963 if (special_static != SPECIAL_STATIC_NONE) {
1964 guint32 size, offset;
1966 gsize default_bitmap [4] = {0};
1971 if (mono_type_is_reference (field->type)) {
1972 default_bitmap [0] = 1;
1974 bitmap = default_bitmap;
1975 } else if (mono_type_is_struct (field->type)) {
1976 fclass = mono_class_from_mono_type (field->type);
1977 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1978 numbits = max_set + 1;
1980 default_bitmap [0] = 0;
1982 bitmap = default_bitmap;
1984 size = mono_type_size (field->type, &align);
1985 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1986 if (!domain->special_static_fields)
1987 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1988 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1989 if (bitmap != default_bitmap)
1992 * This marks the field as special static to speed up the
1993 * checks in mono_field_static_get/set_value ().
1999 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2000 MonoClass *fklass = mono_class_from_mono_type (field->type);
2001 const char *data = mono_field_get_data (field);
2003 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2004 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2005 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2008 if (fklass->valuetype) {
2009 memcpy (t, data, mono_class_value_size (fklass, NULL));
2011 /* it's a pointer type: add check */
2012 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2019 vt->max_interface_id = klass->max_interface_id;
2020 vt->interface_bitmap = klass->interface_bitmap;
2022 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2023 // class->name, klass->interface_offsets_count);
2025 /* Initialize vtable */
2026 if (callbacks.get_vtable_trampoline) {
2027 // This also covers the AOT case
2028 for (i = 0; i < klass->vtable_size; ++i) {
2029 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2032 mono_class_setup_vtable (klass);
2034 for (i = 0; i < klass->vtable_size; ++i) {
2037 cm = klass->vtable [i];
2039 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2040 if (!is_ok (error)) {
2041 mono_domain_unlock (domain);
2042 mono_loader_unlock ();
2049 if (imt_table_bytes) {
2050 /* Now that the vtable is full, we can actually fill up the IMT */
2051 for (i = 0; i < MONO_IMT_SIZE; ++i)
2052 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2056 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2057 * re-acquire them and check if another thread has created the vtable in the meantime.
2059 /* Special case System.MonoType to avoid infinite recursion */
2060 if (klass != mono_defaults.runtimetype_class) {
2061 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2062 if (!is_ok (error)) {
2063 mono_domain_unlock (domain);
2064 mono_loader_unlock ();
2068 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2069 /* This is unregistered in
2070 unregister_vtable_reflection_type() in
2072 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2075 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2077 /* class_vtable_array keeps an array of created vtables
2079 g_ptr_array_add (domain->class_vtable_array, vt);
2080 /* klass->runtime_info is protected by the loader lock, both when
2081 * it it enlarged and when it is stored info.
2085 * Store the vtable in klass->runtime_info.
2086 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2088 mono_memory_barrier ();
2090 old_info = klass->runtime_info;
2091 if (old_info && old_info->max_domain >= domain->domain_id) {
2092 /* someone already created a large enough runtime info */
2093 old_info->domain_vtables [domain->domain_id] = vt;
2095 int new_size = domain->domain_id;
2097 new_size = MAX (new_size, old_info->max_domain);
2099 /* make the new size a power of two */
2101 while (new_size > i)
2104 /* this is a bounded memory retention issue: may want to
2105 * handle it differently when we'll have a rcu-like system.
2107 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2108 runtime_info->max_domain = new_size - 1;
2109 /* copy the stuff from the older info */
2111 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2113 runtime_info->domain_vtables [domain->domain_id] = vt;
2115 mono_memory_barrier ();
2116 klass->runtime_info = runtime_info;
2119 if (klass == mono_defaults.runtimetype_class) {
2120 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2121 if (!is_ok (error)) {
2122 mono_domain_unlock (domain);
2123 mono_loader_unlock ();
2127 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2128 /* This is unregistered in
2129 unregister_vtable_reflection_type() in
2131 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2134 mono_domain_unlock (domain);
2135 mono_loader_unlock ();
2137 /* make sure the parent is initialized */
2138 /*FIXME shouldn't this fail the current type?*/
2140 mono_class_vtable_full (domain, klass->parent, error);
2145 #ifndef DISABLE_REMOTING
2147 * mono_class_proxy_vtable:
2148 * @domain: the application domain
2149 * @remove_class: the remote class
2150 * @error: set on error
2152 * Creates a vtable for transparent proxies. It is basically
2153 * a copy of the real vtable of the class wrapped in @remote_class,
2154 * but all function pointers invoke the remoting functions, and
2155 * vtable->klass points to the transparent proxy class, and not to @class.
2157 * On failure returns NULL and sets @error
2160 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2162 MONO_REQ_GC_UNSAFE_MODE;
2164 MonoVTable *vt, *pvt;
2165 int i, j, vtsize, extra_interface_vtsize = 0;
2166 guint32 max_interface_id;
2168 GSList *extra_interfaces = NULL;
2169 MonoClass *klass = remote_class->proxy_class;
2170 gpointer *interface_offsets;
2171 uint8_t *bitmap = NULL;
2173 size_t imt_table_bytes;
2175 #ifdef COMPRESSED_INTERFACE_BITMAP
2179 mono_error_init (error);
2181 vt = mono_class_vtable (domain, klass);
2182 g_assert (vt); /*FIXME property handle failure*/
2183 max_interface_id = vt->max_interface_id;
2185 /* Calculate vtable space for extra interfaces */
2186 for (j = 0; j < remote_class->interface_count; j++) {
2187 MonoClass* iclass = remote_class->interfaces[j];
2191 /*FIXME test for interfaces with variant generic arguments*/
2192 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2193 continue; /* interface implemented by the class */
2194 if (g_slist_find (extra_interfaces, iclass))
2197 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2199 method_count = mono_class_num_methods (iclass);
2201 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2205 for (i = 0; i < ifaces->len; ++i) {
2206 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2207 /*FIXME test for interfaces with variant generic arguments*/
2208 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2209 continue; /* interface implemented by the class */
2210 if (g_slist_find (extra_interfaces, ic))
2212 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2213 method_count += mono_class_num_methods (ic);
2215 g_ptr_array_free (ifaces, TRUE);
2219 extra_interface_vtsize += method_count * sizeof (gpointer);
2220 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2223 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2224 mono_stats.imt_number_of_tables++;
2225 mono_stats.imt_tables_size += imt_table_bytes;
2227 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2229 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2231 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2232 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2233 g_assert (!((gsize)pvt & 7));
2235 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2237 pvt->klass = mono_defaults.transparent_proxy_class;
2238 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2239 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2241 /* initialize vtable */
2242 mono_class_setup_vtable (klass);
2243 for (i = 0; i < klass->vtable_size; ++i) {
2246 if ((cm = klass->vtable [i])) {
2247 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2251 pvt->vtable [i] = NULL;
2254 if (mono_class_is_abstract (klass)) {
2255 /* create trampolines for abstract methods */
2256 for (k = klass; k; k = k->parent) {
2258 gpointer iter = NULL;
2259 while ((m = mono_class_get_methods (k, &iter)))
2260 if (!pvt->vtable [m->slot]) {
2261 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2268 pvt->max_interface_id = max_interface_id;
2269 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2270 #ifdef COMPRESSED_INTERFACE_BITMAP
2271 bitmap = (uint8_t *)g_malloc0 (bsize);
2273 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2276 for (i = 0; i < klass->interface_offsets_count; ++i) {
2277 int interface_id = klass->interfaces_packed [i]->interface_id;
2278 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2281 if (extra_interfaces) {
2282 int slot = klass->vtable_size;
2288 /* Create trampolines for the methods of the interfaces */
2289 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2290 interf = (MonoClass *)list_item->data;
2292 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2296 while ((cm = mono_class_get_methods (interf, &iter))) {
2297 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2302 slot += mono_class_num_methods (interf);
2306 /* Now that the vtable is full, we can actually fill up the IMT */
2307 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2308 if (extra_interfaces) {
2309 g_slist_free (extra_interfaces);
2312 #ifdef COMPRESSED_INTERFACE_BITMAP
2313 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2314 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2315 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2318 pvt->interface_bitmap = bitmap;
2322 if (extra_interfaces)
2323 g_slist_free (extra_interfaces);
2324 #ifdef COMPRESSED_INTERFACE_BITMAP
2330 #endif /* DISABLE_REMOTING */
2333 * mono_class_field_is_special_static:
2335 * Returns whether @field is a thread/context static field.
2338 mono_class_field_is_special_static (MonoClassField *field)
2340 MONO_REQ_GC_NEUTRAL_MODE
2342 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2344 if (mono_field_is_deleted (field))
2346 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2347 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2354 * mono_class_field_get_special_static_type:
2355 * @field: The MonoClassField describing the field.
2357 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2358 * SPECIAL_STATIC_NONE otherwise.
2361 mono_class_field_get_special_static_type (MonoClassField *field)
2363 MONO_REQ_GC_NEUTRAL_MODE
2365 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2366 return SPECIAL_STATIC_NONE;
2367 if (mono_field_is_deleted (field))
2368 return SPECIAL_STATIC_NONE;
2369 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2370 return field_is_special_static (field->parent, field);
2371 return SPECIAL_STATIC_NONE;
2375 * mono_class_has_special_static_fields:
2377 * Returns whenever @klass has any thread/context static fields.
2380 mono_class_has_special_static_fields (MonoClass *klass)
2382 MONO_REQ_GC_NEUTRAL_MODE
2384 MonoClassField *field;
2388 while ((field = mono_class_get_fields (klass, &iter))) {
2389 g_assert (field->parent == klass);
2390 if (mono_class_field_is_special_static (field))
2397 #ifndef DISABLE_REMOTING
2399 * create_remote_class_key:
2400 * Creates an array of pointers that can be used as a hash key for a remote class.
2401 * The first element of the array is the number of pointers.
2404 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2406 MONO_REQ_GC_NEUTRAL_MODE;
2411 if (remote_class == NULL) {
2412 if (mono_class_is_interface (extra_class)) {
2413 key = (void **)g_malloc (sizeof(gpointer) * 3);
2414 key [0] = GINT_TO_POINTER (2);
2415 key [1] = mono_defaults.marshalbyrefobject_class;
2416 key [2] = extra_class;
2418 key = (void **)g_malloc (sizeof(gpointer) * 2);
2419 key [0] = GINT_TO_POINTER (1);
2420 key [1] = extra_class;
2423 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2424 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2425 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2426 key [1] = remote_class->proxy_class;
2428 // Keep the list of interfaces sorted
2429 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2430 if (extra_class && remote_class->interfaces [i] > extra_class) {
2431 key [j++] = extra_class;
2434 key [j] = remote_class->interfaces [i];
2437 key [j] = extra_class;
2439 // Replace the old class. The interface list is the same
2440 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2441 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2442 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2443 for (i = 0; i < remote_class->interface_count; i++)
2444 key [2 + i] = remote_class->interfaces [i];
2452 * copy_remote_class_key:
2454 * Make a copy of KEY in the domain and return the copy.
2457 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2459 MONO_REQ_GC_NEUTRAL_MODE
2461 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2462 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2464 memcpy (mp_key, key, key_size);
2470 * mono_remote_class:
2471 * @domain: the application domain
2472 * @class_name: name of the remote class
2473 * @error: set on error
2475 * Creates and initializes a MonoRemoteClass object for a remote type.
2477 * On failure returns NULL and sets @error
2480 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2482 MONO_REQ_GC_UNSAFE_MODE;
2484 MonoRemoteClass *rc;
2485 gpointer* key, *mp_key;
2488 mono_error_init (error);
2490 key = create_remote_class_key (NULL, proxy_class);
2492 mono_domain_lock (domain);
2493 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2497 mono_domain_unlock (domain);
2501 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2502 if (!is_ok (error)) {
2504 mono_domain_unlock (domain);
2508 mp_key = copy_remote_class_key (domain, key);
2512 if (mono_class_is_interface (proxy_class)) {
2513 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2514 rc->interface_count = 1;
2515 rc->interfaces [0] = proxy_class;
2516 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2518 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2519 rc->interface_count = 0;
2520 rc->proxy_class = proxy_class;
2523 rc->default_vtable = NULL;
2524 rc->xdomain_vtable = NULL;
2525 rc->proxy_class_name = name;
2526 #ifndef DISABLE_PERFCOUNTERS
2527 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2530 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2532 mono_domain_unlock (domain);
2537 * clone_remote_class:
2538 * Creates a copy of the remote_class, adding the provided class or interface
2540 static MonoRemoteClass*
2541 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2543 MONO_REQ_GC_NEUTRAL_MODE;
2545 MonoRemoteClass *rc;
2546 gpointer* key, *mp_key;
2548 key = create_remote_class_key (remote_class, extra_class);
2549 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2555 mp_key = copy_remote_class_key (domain, key);
2559 if (mono_class_is_interface (extra_class)) {
2561 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2562 rc->proxy_class = remote_class->proxy_class;
2563 rc->interface_count = remote_class->interface_count + 1;
2565 // Keep the list of interfaces sorted, since the hash key of
2566 // the remote class depends on this
2567 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2568 if (remote_class->interfaces [i] > extra_class && i == j)
2569 rc->interfaces [j++] = extra_class;
2570 rc->interfaces [j] = remote_class->interfaces [i];
2573 rc->interfaces [j] = extra_class;
2575 // Replace the old class. The interface array is the same
2576 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2577 rc->proxy_class = extra_class;
2578 rc->interface_count = remote_class->interface_count;
2579 if (rc->interface_count > 0)
2580 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2583 rc->default_vtable = NULL;
2584 rc->xdomain_vtable = NULL;
2585 rc->proxy_class_name = remote_class->proxy_class_name;
2587 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2593 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2595 MONO_REQ_GC_UNSAFE_MODE;
2597 mono_error_init (error);
2599 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2600 mono_domain_lock (domain);
2601 if (rp->target_domain_id != -1) {
2602 if (remote_class->xdomain_vtable == NULL)
2603 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2604 mono_domain_unlock (domain);
2605 mono_loader_unlock ();
2606 return_val_if_nok (error, NULL);
2607 return remote_class->xdomain_vtable;
2609 if (remote_class->default_vtable == NULL) {
2612 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2613 klass = mono_class_from_mono_type (type);
2615 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)))
2616 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2619 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2620 /* N.B. both branches of the if modify error */
2621 if (!is_ok (error)) {
2622 mono_domain_unlock (domain);
2623 mono_loader_unlock ();
2628 mono_domain_unlock (domain);
2629 mono_loader_unlock ();
2630 return remote_class->default_vtable;
2634 * mono_upgrade_remote_class:
2635 * @domain: the application domain
2636 * @tproxy: the proxy whose remote class has to be upgraded.
2637 * @klass: class to which the remote class can be casted.
2638 * @error: set on error
2640 * Updates the vtable of the remote class by adding the necessary method slots
2641 * and interface offsets so it can be safely casted to klass. klass can be a
2642 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2645 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2647 MONO_REQ_GC_UNSAFE_MODE;
2649 MonoTransparentProxy *tproxy;
2650 MonoRemoteClass *remote_class;
2651 gboolean redo_vtable;
2653 mono_error_init (error);
2654 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2655 mono_domain_lock (domain);
2657 tproxy = (MonoTransparentProxy*) proxy_object;
2658 remote_class = tproxy->remote_class;
2660 if (mono_class_is_interface (klass)) {
2663 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2664 if (remote_class->interfaces [i] == klass)
2665 redo_vtable = FALSE;
2668 redo_vtable = (remote_class->proxy_class != klass);
2672 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2673 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2679 mono_domain_unlock (domain);
2680 mono_loader_unlock ();
2681 return is_ok (error);
2683 #endif /* DISABLE_REMOTING */
2687 * mono_object_get_virtual_method:
2688 * @obj: object to operate on.
2691 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2692 * the instance of a callvirt of method.
2695 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2697 MONO_REQ_GC_UNSAFE_MODE;
2700 MonoMethod **vtable;
2701 gboolean is_proxy = FALSE;
2702 MonoMethod *res = NULL;
2704 klass = mono_object_class (obj);
2705 #ifndef DISABLE_REMOTING
2706 if (klass == mono_defaults.transparent_proxy_class) {
2707 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2712 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2715 mono_class_setup_vtable (klass);
2716 vtable = klass->vtable;
2718 if (method->slot == -1) {
2719 /* method->slot might not be set for instances of generic methods */
2720 if (method->is_inflated) {
2721 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2722 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2725 g_assert_not_reached ();
2729 /* check method->slot is a valid index: perform isinstance? */
2730 if (method->slot != -1) {
2731 if (mono_class_is_interface (method->klass)) {
2733 gboolean variance_used = FALSE;
2734 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2735 g_assert (iface_offset > 0);
2736 res = vtable [iface_offset + method->slot];
2739 res = vtable [method->slot];
2743 #ifndef DISABLE_REMOTING
2745 /* It may be an interface, abstract class method or generic method */
2746 if (!res || mono_method_signature (res)->generic_param_count)
2749 /* generic methods demand invoke_with_check */
2750 if (mono_method_signature (res)->generic_param_count)
2751 res = mono_marshal_get_remoting_invoke_with_check (res);
2754 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2755 res = mono_cominterop_get_invoke (res);
2758 res = mono_marshal_get_remoting_invoke (res);
2763 if (method->is_inflated) {
2765 /* Have to inflate the result */
2766 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2767 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2777 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2779 MONO_REQ_GC_UNSAFE_MODE;
2781 MonoObject *result = NULL;
2783 g_assert (callbacks.runtime_invoke);
2785 mono_error_init (error);
2787 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2788 mono_profiler_method_start_invoke (method);
2790 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2792 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2793 mono_profiler_method_end_invoke (method);
2795 if (!mono_error_ok (error))
2802 * mono_runtime_invoke:
2803 * @method: method to invoke
2804 * @obJ: object instance
2805 * @params: arguments to the method
2806 * @exc: exception information.
2808 * Invokes the method represented by @method on the object @obj.
2810 * obj is the 'this' pointer, it should be NULL for static
2811 * methods, a MonoObject* for object instances and a pointer to
2812 * the value type for value types.
2814 * The params array contains the arguments to the method with the
2815 * same convention: MonoObject* pointers for object instances and
2816 * pointers to the value type otherwise.
2818 * From unmanaged code you'll usually use the
2819 * mono_runtime_invoke() variant.
2821 * Note that this function doesn't handle virtual methods for
2822 * you, it will exec the exact method you pass: we still need to
2823 * expose a function to lookup the derived class implementation
2824 * of a virtual method (there are examples of this in the code,
2827 * You can pass NULL as the exc argument if you don't want to
2828 * catch exceptions, otherwise, *exc will be set to the exception
2829 * thrown, if any. if an exception is thrown, you can't use the
2830 * MonoObject* result from the function.
2832 * If the method returns a value type, it is boxed in an object
2836 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2841 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2842 if (*exc == NULL && !mono_error_ok(&error)) {
2843 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2845 mono_error_cleanup (&error);
2847 res = mono_runtime_invoke_checked (method, obj, params, &error);
2848 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2854 * mono_runtime_try_invoke:
2855 * @method: method to invoke
2856 * @obJ: object instance
2857 * @params: arguments to the method
2858 * @exc: exception information.
2859 * @error: set on error
2861 * Invokes the method represented by @method on the object @obj.
2863 * obj is the 'this' pointer, it should be NULL for static
2864 * methods, a MonoObject* for object instances and a pointer to
2865 * the value type for value types.
2867 * The params array contains the arguments to the method with the
2868 * same convention: MonoObject* pointers for object instances and
2869 * pointers to the value type otherwise.
2871 * From unmanaged code you'll usually use the
2872 * mono_runtime_invoke() variant.
2874 * Note that this function doesn't handle virtual methods for
2875 * you, it will exec the exact method you pass: we still need to
2876 * expose a function to lookup the derived class implementation
2877 * of a virtual method (there are examples of this in the code,
2880 * For this function, you must not pass NULL as the exc argument if
2881 * you don't want to catch exceptions, use
2882 * mono_runtime_invoke_checked(). If an exception is thrown, you
2883 * can't use the MonoObject* result from the function.
2885 * If this method cannot be invoked, @error will be set and @exc and
2886 * the return value must not be used.
2888 * If the method returns a value type, it is boxed in an object
2892 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2894 MONO_REQ_GC_UNSAFE_MODE;
2896 g_assert (exc != NULL);
2898 if (mono_runtime_get_no_exec ())
2899 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2901 return do_runtime_invoke (method, obj, params, exc, error);
2905 * mono_runtime_invoke_checked:
2906 * @method: method to invoke
2907 * @obJ: object instance
2908 * @params: arguments to the method
2909 * @error: set on error
2911 * Invokes the method represented by @method on the object @obj.
2913 * obj is the 'this' pointer, it should be NULL for static
2914 * methods, a MonoObject* for object instances and a pointer to
2915 * the value type for value types.
2917 * The params array contains the arguments to the method with the
2918 * same convention: MonoObject* pointers for object instances and
2919 * pointers to the value type otherwise.
2921 * From unmanaged code you'll usually use the
2922 * mono_runtime_invoke() variant.
2924 * Note that this function doesn't handle virtual methods for
2925 * you, it will exec the exact method you pass: we still need to
2926 * expose a function to lookup the derived class implementation
2927 * of a virtual method (there are examples of this in the code,
2930 * If an exception is thrown, you can't use the MonoObject* result
2931 * from the function.
2933 * If this method cannot be invoked, @error will be set. If the
2934 * method throws an exception (and we're in coop mode) the exception
2935 * will be set in @error.
2937 * If the method returns a value type, it is boxed in an object
2941 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2943 MONO_REQ_GC_UNSAFE_MODE;
2945 if (mono_runtime_get_no_exec ())
2946 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2948 return do_runtime_invoke (method, obj, params, NULL, error);
2952 * mono_method_get_unmanaged_thunk:
2953 * @method: method to generate a thunk for.
2955 * Returns an unmanaged->managed thunk that can be used to call
2956 * a managed method directly from C.
2958 * The thunk's C signature closely matches the managed signature:
2960 * C#: public bool Equals (object obj);
2961 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2962 * MonoObject*, MonoException**);
2964 * The 1st ("this") parameter must not be used with static methods:
2966 * C#: public static bool ReferenceEquals (object a, object b);
2967 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2970 * The last argument must be a non-null pointer of a MonoException* pointer.
2971 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2972 * exception has been thrown in managed code. Otherwise it will point
2973 * to the MonoException* caught by the thunk. In this case, the result of
2974 * the thunk is undefined:
2976 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2977 * MonoException *ex = NULL;
2978 * Equals func = mono_method_get_unmanaged_thunk (method);
2979 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2981 * // handle exception
2984 * The calling convention of the thunk matches the platform's default
2985 * convention. This means that under Windows, C declarations must
2986 * contain the __stdcall attribute:
2988 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2989 * MonoObject*, MonoException**);
2993 * Value type arguments and return values are treated as they were objects:
2995 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2996 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2998 * Arguments must be properly boxed upon trunk's invocation, while return
2999 * values must be unboxed.
3002 mono_method_get_unmanaged_thunk (MonoMethod *method)
3004 MONO_REQ_GC_NEUTRAL_MODE;
3005 MONO_REQ_API_ENTRYPOINT;
3010 g_assert (!mono_threads_is_coop_enabled ());
3012 MONO_ENTER_GC_UNSAFE;
3013 method = mono_marshal_get_thunk_invoke_wrapper (method);
3014 res = mono_compile_method_checked (method, &error);
3015 mono_error_cleanup (&error);
3016 MONO_EXIT_GC_UNSAFE;
3022 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3024 MONO_REQ_GC_UNSAFE_MODE;
3028 /* object fields cannot be byref, so we don't need a
3030 gpointer *p = (gpointer*)dest;
3037 case MONO_TYPE_BOOLEAN:
3039 case MONO_TYPE_U1: {
3040 guint8 *p = (guint8*)dest;
3041 *p = value ? *(guint8*)value : 0;
3046 case MONO_TYPE_CHAR: {
3047 guint16 *p = (guint16*)dest;
3048 *p = value ? *(guint16*)value : 0;
3051 #if SIZEOF_VOID_P == 4
3056 case MONO_TYPE_U4: {
3057 gint32 *p = (gint32*)dest;
3058 *p = value ? *(gint32*)value : 0;
3061 #if SIZEOF_VOID_P == 8
3066 case MONO_TYPE_U8: {
3067 gint64 *p = (gint64*)dest;
3068 *p = value ? *(gint64*)value : 0;
3071 case MONO_TYPE_R4: {
3072 float *p = (float*)dest;
3073 *p = value ? *(float*)value : 0;
3076 case MONO_TYPE_R8: {
3077 double *p = (double*)dest;
3078 *p = value ? *(double*)value : 0;
3081 case MONO_TYPE_STRING:
3082 case MONO_TYPE_SZARRAY:
3083 case MONO_TYPE_CLASS:
3084 case MONO_TYPE_OBJECT:
3085 case MONO_TYPE_ARRAY:
3086 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3088 case MONO_TYPE_FNPTR:
3089 case MONO_TYPE_PTR: {
3090 gpointer *p = (gpointer*)dest;
3091 *p = deref_pointer? *(gpointer*)value: value;
3094 case MONO_TYPE_VALUETYPE:
3095 /* note that 't' and 'type->type' can be different */
3096 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3097 t = mono_class_enum_basetype (type->data.klass)->type;
3100 MonoClass *klass = mono_class_from_mono_type (type);
3101 int size = mono_class_value_size (klass, NULL);
3103 mono_gc_bzero_atomic (dest, size);
3105 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3108 case MONO_TYPE_GENERICINST:
3109 t = type->data.generic_class->container_class->byval_arg.type;
3112 g_error ("got type %x", type->type);
3117 * mono_field_set_value:
3118 * @obj: Instance object
3119 * @field: MonoClassField describing the field to set
3120 * @value: The value to be set
3122 * Sets the value of the field described by @field in the object instance @obj
3123 * to the value passed in @value. This method should only be used for instance
3124 * fields. For static fields, use mono_field_static_set_value.
3126 * The value must be on the native format of the field type.
3129 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3131 MONO_REQ_GC_UNSAFE_MODE;
3135 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3137 dest = (char*)obj + field->offset;
3138 mono_copy_value (field->type, dest, value, FALSE);
3142 * mono_field_static_set_value:
3143 * @field: MonoClassField describing the field to set
3144 * @value: The value to be set
3146 * Sets the value of the static field described by @field
3147 * to the value passed in @value.
3149 * The value must be on the native format of the field type.
3152 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3154 MONO_REQ_GC_UNSAFE_MODE;
3158 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3159 /* you cant set a constant! */
3160 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3162 if (field->offset == -1) {
3163 /* Special static */
3166 mono_domain_lock (vt->domain);
3167 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3168 mono_domain_unlock (vt->domain);
3169 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3171 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3173 mono_copy_value (field->type, dest, value, FALSE);
3177 * mono_vtable_get_static_field_data:
3179 * Internal use function: return a pointer to the memory holding the static fields
3180 * for a class or NULL if there are no static fields.
3181 * This is exported only for use by the debugger.
3184 mono_vtable_get_static_field_data (MonoVTable *vt)
3186 MONO_REQ_GC_NEUTRAL_MODE
3188 if (!vt->has_static_fields)
3190 return vt->vtable [vt->klass->vtable_size];
3194 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3196 MONO_REQ_GC_UNSAFE_MODE;
3200 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3201 if (field->offset == -1) {
3202 /* Special static */
3205 mono_domain_lock (vt->domain);
3206 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3207 mono_domain_unlock (vt->domain);
3208 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3210 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3213 src = (guint8*)obj + field->offset;
3220 * mono_field_get_value:
3221 * @obj: Object instance
3222 * @field: MonoClassField describing the field to fetch information from
3223 * @value: pointer to the location where the value will be stored
3225 * Use this routine to get the value of the field @field in the object
3228 * The pointer provided by value must be of the field type, for reference
3229 * types this is a MonoObject*, for value types its the actual pointer to
3234 * mono_field_get_value (obj, int_field, &i);
3237 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3239 MONO_REQ_GC_UNSAFE_MODE;
3245 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3247 src = (char*)obj + field->offset;
3248 mono_copy_value (field->type, value, src, TRUE);
3252 * mono_field_get_value_object:
3253 * @domain: domain where the object will be created (if boxing)
3254 * @field: MonoClassField describing the field to fetch information from
3255 * @obj: The object instance for the field.
3257 * Returns: a new MonoObject with the value from the given field. If the
3258 * field represents a value type, the value is boxed.
3262 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3265 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3266 mono_error_assert_ok (&error);
3271 * mono_field_get_value_object_checked:
3272 * @domain: domain where the object will be created (if boxing)
3273 * @field: MonoClassField describing the field to fetch information from
3274 * @obj: The object instance for the field.
3275 * @error: Set on error.
3277 * Returns: a new MonoObject with the value from the given field. If the
3278 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3282 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3284 MONO_REQ_GC_UNSAFE_MODE;
3286 mono_error_init (error);
3290 MonoVTable *vtable = NULL;
3292 gboolean is_static = FALSE;
3293 gboolean is_ref = FALSE;
3294 gboolean is_literal = FALSE;
3295 gboolean is_ptr = FALSE;
3296 MonoType *type = mono_field_get_type_checked (field, error);
3298 return_val_if_nok (error, NULL);
3300 switch (type->type) {
3301 case MONO_TYPE_STRING:
3302 case MONO_TYPE_OBJECT:
3303 case MONO_TYPE_CLASS:
3304 case MONO_TYPE_ARRAY:
3305 case MONO_TYPE_SZARRAY:
3310 case MONO_TYPE_BOOLEAN:
3313 case MONO_TYPE_CHAR:
3322 case MONO_TYPE_VALUETYPE:
3323 is_ref = type->byref;
3325 case MONO_TYPE_GENERICINST:
3326 is_ref = !mono_type_generic_inst_is_valuetype (type);
3332 g_error ("type 0x%x not handled in "
3333 "mono_field_get_value_object", type->type);
3337 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3340 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3344 vtable = mono_class_vtable_full (domain, field->parent, error);
3345 return_val_if_nok (error, NULL);
3347 if (!vtable->initialized) {
3348 mono_runtime_class_init_full (vtable, error);
3349 return_val_if_nok (error, NULL);
3358 get_default_field_value (domain, field, &o, error);
3359 return_val_if_nok (error, NULL);
3360 } else if (is_static) {
3361 mono_field_static_get_value_checked (vtable, field, &o, error);
3362 return_val_if_nok (error, NULL);
3364 mono_field_get_value (obj, field, &o);
3370 static MonoMethod *m;
3376 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3377 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3383 get_default_field_value (domain, field, v, error);
3384 return_val_if_nok (error, NULL);
3385 } else if (is_static) {
3386 mono_field_static_get_value_checked (vtable, field, v, error);
3387 return_val_if_nok (error, NULL);
3389 mono_field_get_value (obj, field, v);
3392 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3393 args [0] = ptr ? *ptr : NULL;
3394 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3395 return_val_if_nok (error, NULL);
3397 o = mono_runtime_invoke_checked (m, NULL, args, error);
3398 return_val_if_nok (error, NULL);
3403 /* boxed value type */
3404 klass = mono_class_from_mono_type (type);
3406 if (mono_class_is_nullable (klass))
3407 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3409 o = mono_object_new_checked (domain, klass, error);
3410 return_val_if_nok (error, NULL);
3411 v = ((gchar *) o) + sizeof (MonoObject);
3414 get_default_field_value (domain, field, v, error);
3415 return_val_if_nok (error, NULL);
3416 } else if (is_static) {
3417 mono_field_static_get_value_checked (vtable, field, v, error);
3418 return_val_if_nok (error, NULL);
3420 mono_field_get_value (obj, field, v);
3427 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3429 MONO_REQ_GC_UNSAFE_MODE;
3431 mono_error_init (error);
3433 const char *p = blob;
3434 mono_metadata_decode_blob_size (p, &p);
3437 case MONO_TYPE_BOOLEAN:
3440 *(guint8 *) value = *p;
3442 case MONO_TYPE_CHAR:
3445 *(guint16*) value = read16 (p);
3449 *(guint32*) value = read32 (p);
3453 *(guint64*) value = read64 (p);
3456 readr4 (p, (float*) value);
3459 readr8 (p, (double*) value);
3461 case MONO_TYPE_STRING:
3462 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3464 case MONO_TYPE_CLASS:
3465 *(gpointer*) value = NULL;
3469 g_warning ("type 0x%02x should not be in constant table", type);
3475 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3477 MONO_REQ_GC_NEUTRAL_MODE;
3479 MonoTypeEnum def_type;
3482 mono_error_init (error);
3484 data = mono_class_get_field_default_value (field, &def_type);
3485 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3489 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3491 MONO_REQ_GC_UNSAFE_MODE;
3495 mono_error_init (error);
3497 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3499 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3500 get_default_field_value (vt->domain, field, value, error);
3504 if (field->offset == -1) {
3505 /* Special static */
3506 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3507 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3509 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3511 mono_copy_value (field->type, value, src, TRUE);
3515 * mono_field_static_get_value:
3516 * @vt: vtable to the object
3517 * @field: MonoClassField describing the field to fetch information from
3518 * @value: where the value is returned
3520 * Use this routine to get the value of the static field @field value.
3522 * The pointer provided by value must be of the field type, for reference
3523 * types this is a MonoObject*, for value types its the actual pointer to
3528 * mono_field_static_get_value (vt, int_field, &i);
3531 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3533 MONO_REQ_GC_NEUTRAL_MODE;
3536 mono_field_static_get_value_checked (vt, field, value, &error);
3537 mono_error_cleanup (&error);
3541 * mono_field_static_get_value_checked:
3542 * @vt: vtable to the object
3543 * @field: MonoClassField describing the field to fetch information from
3544 * @value: where the value is returned
3545 * @error: set on error
3547 * Use this routine to get the value of the static field @field value.
3549 * The pointer provided by value must be of the field type, for reference
3550 * types this is a MonoObject*, for value types its the actual pointer to
3555 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3556 * if (!is_ok (error)) { ... }
3558 * On failure sets @error.
3561 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3563 MONO_REQ_GC_NEUTRAL_MODE;
3565 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3569 * mono_property_set_value:
3570 * @prop: MonoProperty to set
3571 * @obj: instance object on which to act
3572 * @params: parameters to pass to the propery
3573 * @exc: optional exception
3575 * Invokes the property's set method with the given arguments on the
3576 * object instance obj (or NULL for static properties).
3578 * You can pass NULL as the exc argument if you don't want to
3579 * catch exceptions, otherwise, *exc will be set to the exception
3580 * thrown, if any. if an exception is thrown, you can't use the
3581 * MonoObject* result from the function.
3584 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3586 MONO_REQ_GC_UNSAFE_MODE;
3589 do_runtime_invoke (prop->set, obj, params, exc, &error);
3590 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3591 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3593 mono_error_cleanup (&error);
3598 * mono_property_set_value_checked:
3599 * @prop: MonoProperty to set
3600 * @obj: instance object on which to act
3601 * @params: parameters to pass to the propery
3602 * @error: set on error
3604 * Invokes the property's set method with the given arguments on the
3605 * object instance obj (or NULL for static properties).
3607 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3608 * If an exception is thrown, it will be caught and returned via @error.
3611 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3613 MONO_REQ_GC_UNSAFE_MODE;
3617 mono_error_init (error);
3618 do_runtime_invoke (prop->set, obj, params, &exc, error);
3619 if (exc != NULL && is_ok (error))
3620 mono_error_set_exception_instance (error, (MonoException*)exc);
3621 return is_ok (error);
3625 * mono_property_get_value:
3626 * @prop: MonoProperty to fetch
3627 * @obj: instance object on which to act
3628 * @params: parameters to pass to the propery
3629 * @exc: optional exception
3631 * Invokes the property's get method with the given arguments on the
3632 * object instance obj (or NULL for static properties).
3634 * You can pass NULL as the exc argument if you don't want to
3635 * catch exceptions, otherwise, *exc will be set to the exception
3636 * thrown, if any. if an exception is thrown, you can't use the
3637 * MonoObject* result from the function.
3639 * Returns: the value from invoking the get method on the property.
3642 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3644 MONO_REQ_GC_UNSAFE_MODE;
3647 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3648 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3649 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3651 mono_error_cleanup (&error); /* FIXME don't raise here */
3658 * mono_property_get_value_checked:
3659 * @prop: MonoProperty to fetch
3660 * @obj: instance object on which to act
3661 * @params: parameters to pass to the propery
3662 * @error: set on error
3664 * Invokes the property's get method with the given arguments on the
3665 * object instance obj (or NULL for static properties).
3667 * If an exception is thrown, you can't use the
3668 * MonoObject* result from the function. The exception will be propagated via @error.
3670 * Returns: the value from invoking the get method on the property. On
3671 * failure returns NULL and sets @error.
3674 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3676 MONO_REQ_GC_UNSAFE_MODE;
3679 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3680 if (exc != NULL && !is_ok (error))
3681 mono_error_set_exception_instance (error, (MonoException*) exc);
3689 * mono_nullable_init:
3690 * @buf: The nullable structure to initialize.
3691 * @value: the value to initialize from
3692 * @klass: the type for the object
3694 * Initialize the nullable structure pointed to by @buf from @value which
3695 * should be a boxed value type. The size of @buf should be able to hold
3696 * as much data as the @klass->instance_size (which is the number of bytes
3697 * that will be copies).
3699 * Since Nullables have variable structure, we can not define a C
3700 * structure for them.
3703 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3705 MONO_REQ_GC_UNSAFE_MODE;
3707 MonoClass *param_class = klass->cast_class;
3709 mono_class_setup_fields (klass);
3710 g_assert (klass->fields_inited);
3712 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3713 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3715 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3717 if (param_class->has_references)
3718 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3720 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3722 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3727 * mono_nullable_box:
3728 * @buf: The buffer representing the data to be boxed
3729 * @klass: the type to box it as.
3730 * @error: set on oerr
3732 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3733 * @buf. On failure returns NULL and sets @error
3736 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3738 MONO_REQ_GC_UNSAFE_MODE;
3740 mono_error_init (error);
3741 MonoClass *param_class = klass->cast_class;
3743 mono_class_setup_fields (klass);
3744 g_assert (klass->fields_inited);
3746 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3747 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3749 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3750 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3751 return_val_if_nok (error, NULL);
3752 if (param_class->has_references)
3753 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3755 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3763 * mono_get_delegate_invoke:
3764 * @klass: The delegate class
3766 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3769 mono_get_delegate_invoke (MonoClass *klass)
3771 MONO_REQ_GC_NEUTRAL_MODE;
3775 /* This is called at runtime, so avoid the slower search in metadata */
3776 mono_class_setup_methods (klass);
3777 if (mono_class_has_failure (klass))
3779 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3784 * mono_get_delegate_begin_invoke:
3785 * @klass: The delegate class
3787 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3790 mono_get_delegate_begin_invoke (MonoClass *klass)
3792 MONO_REQ_GC_NEUTRAL_MODE;
3796 /* This is called at runtime, so avoid the slower search in metadata */
3797 mono_class_setup_methods (klass);
3798 if (mono_class_has_failure (klass))
3800 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3805 * mono_get_delegate_end_invoke:
3806 * @klass: The delegate class
3808 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3811 mono_get_delegate_end_invoke (MonoClass *klass)
3813 MONO_REQ_GC_NEUTRAL_MODE;
3817 /* This is called at runtime, so avoid the slower search in metadata */
3818 mono_class_setup_methods (klass);
3819 if (mono_class_has_failure (klass))
3821 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3826 * mono_runtime_delegate_invoke:
3827 * @delegate: pointer to a delegate object.
3828 * @params: parameters for the delegate.
3829 * @exc: Pointer to the exception result.
3831 * Invokes the delegate method @delegate with the parameters provided.
3833 * You can pass NULL as the exc argument if you don't want to
3834 * catch exceptions, otherwise, *exc will be set to the exception
3835 * thrown, if any. if an exception is thrown, you can't use the
3836 * MonoObject* result from the function.
3839 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3841 MONO_REQ_GC_UNSAFE_MODE;
3845 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3847 mono_error_cleanup (&error);
3850 if (!is_ok (&error))
3851 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3855 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3856 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3862 * mono_runtime_delegate_try_invoke:
3863 * @delegate: pointer to a delegate object.
3864 * @params: parameters for the delegate.
3865 * @exc: Pointer to the exception result.
3866 * @error: set on error
3868 * Invokes the delegate method @delegate with the parameters provided.
3870 * You can pass NULL as the exc argument if you don't want to
3871 * catch exceptions, otherwise, *exc will be set to the exception
3872 * thrown, if any. On failure to execute, @error will be set.
3873 * if an exception is thrown, you can't use the
3874 * MonoObject* result from the function.
3877 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3879 MONO_REQ_GC_UNSAFE_MODE;
3881 mono_error_init (error);
3883 MonoClass *klass = delegate->vtable->klass;
3886 im = mono_get_delegate_invoke (klass);
3888 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3891 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3893 o = mono_runtime_invoke_checked (im, delegate, params, error);
3900 * mono_runtime_delegate_invoke_checked:
3901 * @delegate: pointer to a delegate object.
3902 * @params: parameters for the delegate.
3903 * @error: set on error
3905 * Invokes the delegate method @delegate with the parameters provided.
3907 * On failure @error will be set and you can't use the MonoObject*
3908 * result from the function.
3911 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3913 mono_error_init (error);
3914 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3917 static char **main_args = NULL;
3918 static int num_main_args = 0;
3921 * mono_runtime_get_main_args:
3923 * Returns: a MonoArray with the arguments passed to the main program
3926 mono_runtime_get_main_args (void)
3928 MONO_REQ_GC_UNSAFE_MODE;
3930 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3931 mono_error_assert_ok (&error);
3936 * mono_runtime_get_main_args:
3937 * @error: set on error
3939 * Returns: a MonoArray with the arguments passed to the main
3940 * program. On failure returns NULL and sets @error.
3943 mono_runtime_get_main_args_checked (MonoError *error)
3947 MonoDomain *domain = mono_domain_get ();
3949 mono_error_init (error);
3951 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3952 return_val_if_nok (error, NULL);
3954 for (i = 0; i < num_main_args; ++i)
3955 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3961 free_main_args (void)
3963 MONO_REQ_GC_NEUTRAL_MODE;
3967 for (i = 0; i < num_main_args; ++i)
3968 g_free (main_args [i]);
3975 * mono_runtime_set_main_args:
3976 * @argc: number of arguments from the command line
3977 * @argv: array of strings from the command line
3979 * Set the command line arguments from an embedding application that doesn't otherwise call
3980 * mono_runtime_run_main ().
3983 mono_runtime_set_main_args (int argc, char* argv[])
3985 MONO_REQ_GC_NEUTRAL_MODE;
3990 main_args = g_new0 (char*, argc);
3991 num_main_args = argc;
3993 for (i = 0; i < argc; ++i) {
3996 utf8_arg = mono_utf8_from_external (argv[i]);
3997 if (utf8_arg == NULL) {
3998 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3999 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4003 main_args [i] = utf8_arg;
4010 * Prepare an array of arguments in order to execute a standard Main()
4011 * method (argc/argv contains the executable name). This method also
4012 * sets the command line argument value needed by System.Environment.
4016 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4018 MONO_REQ_GC_UNSAFE_MODE;
4022 MonoArray *args = NULL;
4023 MonoDomain *domain = mono_domain_get ();
4024 gchar *utf8_fullpath;
4025 MonoMethodSignature *sig;
4027 g_assert (method != NULL);
4029 mono_thread_set_main (mono_thread_current ());
4031 main_args = g_new0 (char*, argc);
4032 num_main_args = argc;
4034 if (!g_path_is_absolute (argv [0])) {
4035 gchar *basename = g_path_get_basename (argv [0]);
4036 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4040 utf8_fullpath = mono_utf8_from_external (fullpath);
4041 if(utf8_fullpath == NULL) {
4042 /* Printing the arg text will cause glib to
4043 * whinge about "Invalid UTF-8", but at least
4044 * its relevant, and shows the problem text
4047 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4048 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4055 utf8_fullpath = mono_utf8_from_external (argv[0]);
4056 if(utf8_fullpath == NULL) {
4057 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4058 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4063 main_args [0] = utf8_fullpath;
4065 for (i = 1; i < argc; ++i) {
4068 utf8_arg=mono_utf8_from_external (argv[i]);
4069 if(utf8_arg==NULL) {
4070 /* Ditto the comment about Invalid UTF-8 here */
4071 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4072 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4076 main_args [i] = utf8_arg;
4081 sig = mono_method_signature (method);
4083 g_print ("Unable to load Main method.\n");
4087 if (sig->param_count) {
4088 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4089 mono_error_assert_ok (&error);
4090 for (i = 0; i < argc; ++i) {
4091 /* The encodings should all work, given that
4092 * we've checked all these args for the
4095 gchar *str = mono_utf8_from_external (argv [i]);
4096 MonoString *arg = mono_string_new (domain, str);
4097 mono_array_setref (args, i, arg);
4101 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4102 mono_error_assert_ok (&error);
4105 mono_assembly_set_main (method->klass->image->assembly);
4111 * mono_runtime_run_main:
4112 * @method: the method to start the application with (usually Main)
4113 * @argc: number of arguments from the command line
4114 * @argv: array of strings from the command line
4115 * @exc: excetption results
4117 * Execute a standard Main() method (argc/argv contains the
4118 * executable name). This method also sets the command line argument value
4119 * needed by System.Environment.
4124 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4127 MONO_REQ_GC_UNSAFE_MODE;
4130 MonoArray *args = prepare_run_main (method, argc, argv);
4133 res = mono_runtime_try_exec_main (method, args, exc);
4135 res = mono_runtime_exec_main_checked (method, args, &error);
4136 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4142 * mono_runtime_run_main_checked:
4143 * @method: the method to start the application with (usually Main)
4144 * @argc: number of arguments from the command line
4145 * @argv: array of strings from the command line
4146 * @error: set on error
4148 * Execute a standard Main() method (argc/argv contains the
4149 * executable name). This method also sets the command line argument value
4150 * needed by System.Environment. On failure sets @error.
4155 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4158 mono_error_init (error);
4159 MonoArray *args = prepare_run_main (method, argc, argv);
4160 return mono_runtime_exec_main_checked (method, args, error);
4164 * mono_runtime_try_run_main:
4165 * @method: the method to start the application with (usually Main)
4166 * @argc: number of arguments from the command line
4167 * @argv: array of strings from the command line
4168 * @exc: set if Main throws an exception
4169 * @error: set if Main can't be executed
4171 * Execute a standard Main() method (argc/argv contains the executable
4172 * name). This method also sets the command line argument value needed
4173 * by System.Environment. On failure sets @error if Main can't be
4174 * executed or @exc if it threw and exception.
4179 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4183 MonoArray *args = prepare_run_main (method, argc, argv);
4184 return mono_runtime_try_exec_main (method, args, exc);
4189 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4191 static MonoMethod *serialize_method;
4197 if (!serialize_method) {
4198 MonoClass *klass = mono_class_get_remoting_services_class ();
4199 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4202 if (!serialize_method) {
4207 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4212 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4213 if (*exc == NULL && !mono_error_ok (&error))
4214 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4216 mono_error_cleanup (&error);
4225 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4227 MONO_REQ_GC_UNSAFE_MODE;
4229 static MonoMethod *deserialize_method;
4235 if (!deserialize_method) {
4236 MonoClass *klass = mono_class_get_remoting_services_class ();
4237 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4239 if (!deserialize_method) {
4247 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4248 if (*exc == NULL && !mono_error_ok (&error))
4249 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4251 mono_error_cleanup (&error);
4259 #ifndef DISABLE_REMOTING
4261 make_transparent_proxy (MonoObject *obj, MonoError *error)
4263 MONO_REQ_GC_UNSAFE_MODE;
4265 static MonoMethod *get_proxy_method;
4267 MonoDomain *domain = mono_domain_get ();
4268 MonoRealProxy *real_proxy;
4269 MonoReflectionType *reflection_type;
4270 MonoTransparentProxy *transparent_proxy;
4272 mono_error_init (error);
4274 if (!get_proxy_method)
4275 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4277 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4279 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4280 return_val_if_nok (error, NULL);
4281 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4282 return_val_if_nok (error, NULL);
4284 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4285 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4287 MonoObject *exc = NULL;
4289 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4290 if (exc != NULL && is_ok (error))
4291 mono_error_set_exception_instance (error, (MonoException*)exc);
4293 return (MonoObject*) transparent_proxy;
4295 #endif /* DISABLE_REMOTING */
4298 * mono_object_xdomain_representation
4300 * @target_domain: a domain
4301 * @error: set on error.
4303 * Creates a representation of obj in the domain target_domain. This
4304 * is either a copy of obj arrived through via serialization and
4305 * deserialization or a proxy, depending on whether the object is
4306 * serializable or marshal by ref. obj must not be in target_domain.
4308 * If the object cannot be represented in target_domain, NULL is
4309 * returned and @error is set appropriately.
4312 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4314 MONO_REQ_GC_UNSAFE_MODE;
4316 mono_error_init (error);
4317 MonoObject *deserialized = NULL;
4319 #ifndef DISABLE_REMOTING
4320 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4321 deserialized = make_transparent_proxy (obj, error);
4326 gboolean failure = FALSE;
4327 MonoDomain *domain = mono_domain_get ();
4328 MonoObject *serialized;
4329 MonoObject *exc = NULL;
4331 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4332 serialized = serialize_object (obj, &failure, &exc);
4333 mono_domain_set_internal_with_options (target_domain, FALSE);
4335 deserialized = deserialize_object (serialized, &failure, &exc);
4336 if (domain != target_domain)
4337 mono_domain_set_internal_with_options (domain, FALSE);
4339 mono_error_set_exception_instance (error, (MonoException*)exc);
4342 return deserialized;
4345 /* Used in call_unhandled_exception_delegate */
4347 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4349 MONO_REQ_GC_UNSAFE_MODE;
4351 mono_error_init (error);
4354 MonoMethod *method = NULL;
4355 MonoBoolean is_terminating = TRUE;
4358 klass = mono_class_get_unhandled_exception_event_args_class ();
4359 mono_class_init (klass);
4361 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4362 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4366 args [1] = &is_terminating;
4368 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4369 return_val_if_nok (error, NULL);
4371 mono_runtime_invoke_checked (method, obj, args, error);
4372 return_val_if_nok (error, NULL);
4377 /* Used in mono_unhandled_exception */
4379 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4380 MONO_REQ_GC_UNSAFE_MODE;
4383 MonoObject *e = NULL;
4385 MonoDomain *current_domain = mono_domain_get ();
4387 if (domain != current_domain)
4388 mono_domain_set_internal_with_options (domain, FALSE);
4390 g_assert (domain == mono_object_domain (domain->domain));
4392 if (mono_object_domain (exc) != domain) {
4394 exc = mono_object_xdomain_representation (exc, domain, &error);
4396 if (!is_ok (&error)) {
4397 MonoError inner_error;
4398 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4399 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4400 mono_error_assert_ok (&inner_error);
4402 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4403 "System.Runtime.Serialization", "SerializationException",
4404 "Could not serialize unhandled exception.");
4408 g_assert (mono_object_domain (exc) == domain);
4410 pa [0] = domain->domain;
4411 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4412 mono_error_assert_ok (&error);
4413 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4414 if (!is_ok (&error)) {
4416 e = (MonoObject*)mono_error_convert_to_exception (&error);
4418 mono_error_cleanup (&error);
4421 if (domain != current_domain)
4422 mono_domain_set_internal_with_options (current_domain, FALSE);
4425 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4426 if (!mono_error_ok (&error)) {
4427 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4428 mono_error_cleanup (&error);
4430 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4436 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4439 * mono_runtime_unhandled_exception_policy_set:
4440 * @policy: the new policy
4442 * This is a VM internal routine.
4444 * Sets the runtime policy for handling unhandled exceptions.
4447 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4448 runtime_unhandled_exception_policy = policy;
4452 * mono_runtime_unhandled_exception_policy_get:
4454 * This is a VM internal routine.
4456 * Gets the runtime policy for handling unhandled exceptions.
4458 MonoRuntimeUnhandledExceptionPolicy
4459 mono_runtime_unhandled_exception_policy_get (void) {
4460 return runtime_unhandled_exception_policy;
4464 * mono_unhandled_exception:
4465 * @exc: exception thrown
4467 * This is a VM internal routine.
4469 * We call this function when we detect an unhandled exception
4470 * in the default domain.
4472 * It invokes the * UnhandledException event in AppDomain or prints
4473 * a warning to the console
4476 mono_unhandled_exception (MonoObject *exc)
4478 MONO_REQ_GC_UNSAFE_MODE;
4481 MonoClassField *field;
4482 MonoDomain *current_domain, *root_domain;
4483 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4485 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4488 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4491 current_domain = mono_domain_get ();
4492 root_domain = mono_get_root_domain ();
4494 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4495 mono_error_assert_ok (&error);
4496 if (current_domain != root_domain) {
4497 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4498 mono_error_assert_ok (&error);
4501 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4502 mono_print_unhandled_exception (exc);
4504 /* unhandled exception callbacks must not be aborted */
4505 mono_threads_begin_abort_protected_block ();
4506 if (root_appdomain_delegate)
4507 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4508 if (current_appdomain_delegate)
4509 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4510 mono_threads_end_abort_protected_block ();
4513 /* set exitcode only if we will abort the process */
4514 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4515 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4517 mono_environment_exitcode_set (1);
4522 * mono_runtime_exec_managed_code:
4523 * @domain: Application domain
4524 * @main_func: function to invoke from the execution thread
4525 * @main_args: parameter to the main_func
4527 * Launch a new thread to execute a function
4529 * main_func is called back from the thread with main_args as the
4530 * parameter. The callback function is expected to start Main()
4531 * eventually. This function then waits for all managed threads to
4533 * It is not necesseray anymore to execute managed code in a subthread,
4534 * so this function should not be used anymore by default: just
4535 * execute the code and then call mono_thread_manage ().
4538 mono_runtime_exec_managed_code (MonoDomain *domain,
4539 MonoMainThreadFunc main_func,
4543 mono_thread_create_checked (domain, main_func, main_args, &error);
4544 mono_error_assert_ok (&error);
4546 mono_thread_manage ();
4550 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4552 MonoInternalThread* thread = mono_thread_internal_current ();
4553 MonoCustomAttrInfo* cinfo;
4554 gboolean has_stathread_attribute;
4556 if (!domain->entry_assembly) {
4558 MonoAssembly *assembly;
4560 assembly = method->klass->image->assembly;
4561 domain->entry_assembly = assembly;
4562 /* Domains created from another domain already have application_base and configuration_file set */
4563 if (domain->setup->application_base == NULL) {
4564 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4567 if (domain->setup->configuration_file == NULL) {
4568 str = g_strconcat (assembly->image->name, ".config", NULL);
4569 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4571 mono_domain_set_options_from_config (domain);
4575 MonoError cattr_error;
4576 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4577 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4579 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4581 mono_custom_attrs_free (cinfo);
4583 has_stathread_attribute = FALSE;
4585 if (has_stathread_attribute) {
4586 thread->apartment_state = ThreadApartmentState_STA;
4588 thread->apartment_state = ThreadApartmentState_MTA;
4590 mono_thread_init_apartment_state ();
4595 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4597 MONO_REQ_GC_UNSAFE_MODE;
4602 mono_error_init (error);
4607 /* FIXME: check signature of method */
4608 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4610 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4612 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4615 mono_environment_exitcode_set (rval);
4617 mono_runtime_invoke_checked (method, NULL, pa, error);
4629 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4631 MONO_REQ_GC_UNSAFE_MODE;
4641 /* FIXME: check signature of method */
4642 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4643 MonoError inner_error;
4645 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4646 if (*exc == NULL && !mono_error_ok (&inner_error))
4647 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4649 mono_error_cleanup (&inner_error);
4652 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4656 mono_environment_exitcode_set (rval);
4658 MonoError inner_error;
4659 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4660 if (*exc == NULL && !mono_error_ok (&inner_error))
4661 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4663 mono_error_cleanup (&inner_error);
4668 /* If the return type of Main is void, only
4669 * set the exitcode if an exception was thrown
4670 * (we don't want to blow away an
4671 * explicitly-set exit code)
4674 mono_environment_exitcode_set (rval);
4682 * Execute a standard Main() method (args doesn't contain the
4686 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4689 prepare_thread_to_exec_main (mono_object_domain (args), method);
4691 int rval = do_try_exec_main (method, args, exc);
4694 int rval = do_exec_main_checked (method, args, &error);
4695 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4701 * Execute a standard Main() method (args doesn't contain the
4704 * On failure sets @error
4707 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4709 mono_error_init (error);
4710 prepare_thread_to_exec_main (mono_object_domain (args), method);
4711 return do_exec_main_checked (method, args, error);
4715 * Execute a standard Main() method (args doesn't contain the
4718 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4721 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4723 prepare_thread_to_exec_main (mono_object_domain (args), method);
4724 return do_try_exec_main (method, args, exc);
4729 /** invoke_array_extract_argument:
4730 * @params: array of arguments to the method.
4731 * @i: the index of the argument to extract.
4732 * @t: ith type from the method signature.
4733 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4734 * @error: set on error.
4736 * Given an array of method arguments, return the ith one using the corresponding type
4737 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4739 * On failure sets @error and returns NULL.
4742 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4744 MonoType *t_orig = t;
4745 gpointer result = NULL;
4746 mono_error_init (error);
4751 case MONO_TYPE_BOOLEAN:
4754 case MONO_TYPE_CHAR:
4763 case MONO_TYPE_VALUETYPE:
4764 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4765 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4766 result = mono_array_get (params, MonoObject*, i);
4768 *has_byref_nullables = TRUE;
4770 /* MS seems to create the objects if a null is passed in */
4771 if (!mono_array_get (params, MonoObject*, i)) {
4772 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4773 return_val_if_nok (error, NULL);
4774 mono_array_setref (params, i, o);
4779 * We can't pass the unboxed vtype byref to the callee, since
4780 * that would mean the callee would be able to modify boxed
4781 * primitive types. So we (and MS) make a copy of the boxed
4782 * object, pass that to the callee, and replace the original
4783 * boxed object in the arg array with the copy.
4785 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4786 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4787 return_val_if_nok (error, NULL);
4788 mono_array_setref (params, i, copy);
4791 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4794 case MONO_TYPE_STRING:
4795 case MONO_TYPE_OBJECT:
4796 case MONO_TYPE_CLASS:
4797 case MONO_TYPE_ARRAY:
4798 case MONO_TYPE_SZARRAY:
4800 result = mono_array_addr (params, MonoObject*, i);
4801 // FIXME: I need to check this code path
4803 result = mono_array_get (params, MonoObject*, i);
4805 case MONO_TYPE_GENERICINST:
4807 t = &t->data.generic_class->container_class->this_arg;
4809 t = &t->data.generic_class->container_class->byval_arg;
4811 case MONO_TYPE_PTR: {
4814 /* The argument should be an IntPtr */
4815 arg = mono_array_get (params, MonoObject*, i);
4819 g_assert (arg->vtable->klass == mono_defaults.int_class);
4820 result = ((MonoIntPtr*)arg)->m_value;
4825 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4830 * mono_runtime_invoke_array:
4831 * @method: method to invoke
4832 * @obJ: object instance
4833 * @params: arguments to the method
4834 * @exc: exception information.
4836 * Invokes the method represented by @method on the object @obj.
4838 * obj is the 'this' pointer, it should be NULL for static
4839 * methods, a MonoObject* for object instances and a pointer to
4840 * the value type for value types.
4842 * The params array contains the arguments to the method with the
4843 * same convention: MonoObject* pointers for object instances and
4844 * pointers to the value type otherwise. The _invoke_array
4845 * variant takes a C# object[] as the params argument (MonoArray
4846 * *params): in this case the value types are boxed inside the
4847 * respective reference representation.
4849 * From unmanaged code you'll usually use the
4850 * mono_runtime_invoke_checked() variant.
4852 * Note that this function doesn't handle virtual methods for
4853 * you, it will exec the exact method you pass: we still need to
4854 * expose a function to lookup the derived class implementation
4855 * of a virtual method (there are examples of this in the code,
4858 * You can pass NULL as the exc argument if you don't want to
4859 * catch exceptions, otherwise, *exc will be set to the exception
4860 * thrown, if any. if an exception is thrown, you can't use the
4861 * MonoObject* result from the function.
4863 * If the method returns a value type, it is boxed in an object
4867 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4872 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4874 mono_error_cleanup (&error);
4877 if (!is_ok (&error))
4878 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4882 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4883 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4889 * mono_runtime_invoke_array_checked:
4890 * @method: method to invoke
4891 * @obJ: object instance
4892 * @params: arguments to the method
4893 * @error: set on failure.
4895 * Invokes the method represented by @method on the object @obj.
4897 * obj is the 'this' pointer, it should be NULL for static
4898 * methods, a MonoObject* for object instances and a pointer to
4899 * the value type for value types.
4901 * The params array contains the arguments to the method with the
4902 * same convention: MonoObject* pointers for object instances and
4903 * pointers to the value type otherwise. The _invoke_array
4904 * variant takes a C# object[] as the params argument (MonoArray
4905 * *params): in this case the value types are boxed inside the
4906 * respective reference representation.
4908 * From unmanaged code you'll usually use the
4909 * mono_runtime_invoke_checked() variant.
4911 * Note that this function doesn't handle virtual methods for
4912 * you, it will exec the exact method you pass: we still need to
4913 * expose a function to lookup the derived class implementation
4914 * of a virtual method (there are examples of this in the code,
4917 * On failure or exception, @error will be set. In that case, you
4918 * can't use the MonoObject* result from the function.
4920 * If the method returns a value type, it is boxed in an object
4924 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4927 mono_error_init (error);
4928 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4932 * mono_runtime_try_invoke_array:
4933 * @method: method to invoke
4934 * @obJ: object instance
4935 * @params: arguments to the method
4936 * @exc: exception information.
4937 * @error: set on failure.
4939 * Invokes the method represented by @method on the object @obj.
4941 * obj is the 'this' pointer, it should be NULL for static
4942 * methods, a MonoObject* for object instances and a pointer to
4943 * the value type for value types.
4945 * The params array contains the arguments to the method with the
4946 * same convention: MonoObject* pointers for object instances and
4947 * pointers to the value type otherwise. The _invoke_array
4948 * variant takes a C# object[] as the params argument (MonoArray
4949 * *params): in this case the value types are boxed inside the
4950 * respective reference representation.
4952 * From unmanaged code you'll usually use the
4953 * mono_runtime_invoke_checked() variant.
4955 * Note that this function doesn't handle virtual methods for
4956 * you, it will exec the exact method you pass: we still need to
4957 * expose a function to lookup the derived class implementation
4958 * of a virtual method (there are examples of this in the code,
4961 * You can pass NULL as the exc argument if you don't want to catch
4962 * exceptions, otherwise, *exc will be set to the exception thrown, if
4963 * any. On other failures, @error will be set. If an exception is
4964 * thrown or there's an error, you can't use the MonoObject* result
4965 * from the function.
4967 * If the method returns a value type, it is boxed in an object
4971 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4972 MonoObject **exc, MonoError *error)
4974 MONO_REQ_GC_UNSAFE_MODE;
4976 mono_error_init (error);
4978 MonoMethodSignature *sig = mono_method_signature (method);
4979 gpointer *pa = NULL;
4982 gboolean has_byref_nullables = FALSE;
4984 if (NULL != params) {
4985 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4986 for (i = 0; i < mono_array_length (params); i++) {
4987 MonoType *t = sig->params [i];
4988 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4989 return_val_if_nok (error, NULL);
4993 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4996 if (mono_class_is_nullable (method->klass)) {
4997 /* Need to create a boxed vtype instead */
5003 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5008 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5009 mono_error_assert_ok (error);
5010 g_assert (obj); /*maybe we should raise a TLE instead?*/
5011 #ifndef DISABLE_REMOTING
5012 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5013 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5016 if (method->klass->valuetype)
5017 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5020 } else if (method->klass->valuetype) {
5021 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5022 return_val_if_nok (error, NULL);
5026 mono_runtime_try_invoke (method, o, pa, exc, error);
5028 mono_runtime_invoke_checked (method, o, pa, error);
5031 return (MonoObject *)obj;
5033 if (mono_class_is_nullable (method->klass)) {
5034 MonoObject *nullable;
5036 /* Convert the unboxed vtype into a Nullable structure */
5037 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5038 return_val_if_nok (error, NULL);
5040 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5041 return_val_if_nok (error, NULL);
5042 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5043 obj = mono_object_unbox (nullable);
5046 /* obj must be already unboxed if needed */
5048 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5050 res = mono_runtime_invoke_checked (method, obj, pa, error);
5052 return_val_if_nok (error, NULL);
5054 if (sig->ret->type == MONO_TYPE_PTR) {
5055 MonoClass *pointer_class;
5056 static MonoMethod *box_method;
5058 MonoObject *box_exc;
5061 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5062 * convert it to a Pointer object.
5064 pointer_class = mono_class_get_pointer_class ();
5066 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5068 g_assert (res->vtable->klass == mono_defaults.int_class);
5069 box_args [0] = ((MonoIntPtr*)res)->m_value;
5070 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5071 return_val_if_nok (error, NULL);
5073 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5074 g_assert (box_exc == NULL);
5075 mono_error_assert_ok (error);
5078 if (has_byref_nullables) {
5080 * The runtime invoke wrapper already converted byref nullables back,
5081 * and stored them in pa, we just need to copy them back to the
5084 for (i = 0; i < mono_array_length (params); i++) {
5085 MonoType *t = sig->params [i];
5087 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5088 mono_array_setref (params, i, pa [i]);
5098 * @klass: the class of the object that we want to create
5100 * Returns: a newly created object whose definition is
5101 * looked up using @klass. This will not invoke any constructors,
5102 * so the consumer of this routine has to invoke any constructors on
5103 * its own to initialize the object.
5105 * It returns NULL on failure.
5108 mono_object_new (MonoDomain *domain, MonoClass *klass)
5110 MONO_REQ_GC_UNSAFE_MODE;
5114 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5116 mono_error_cleanup (&error);
5121 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5123 MONO_REQ_GC_UNSAFE_MODE;
5127 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5129 mono_error_set_pending_exception (&error);
5134 * mono_object_new_checked:
5135 * @klass: the class of the object that we want to create
5136 * @error: set on error
5138 * Returns: a newly created object whose definition is
5139 * looked up using @klass. This will not invoke any constructors,
5140 * so the consumer of this routine has to invoke any constructors on
5141 * its own to initialize the object.
5143 * It returns NULL on failure and sets @error.
5146 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5148 MONO_REQ_GC_UNSAFE_MODE;
5152 vtable = mono_class_vtable (domain, klass);
5153 g_assert (vtable); /* FIXME don't swallow the error */
5155 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5160 * mono_object_new_pinned:
5162 * Same as mono_object_new, but the returned object will be pinned.
5163 * For SGEN, these objects will only be freed at appdomain unload.
5166 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5168 MONO_REQ_GC_UNSAFE_MODE;
5172 mono_error_init (error);
5174 vtable = mono_class_vtable (domain, klass);
5175 g_assert (vtable); /* FIXME don't swallow the error */
5177 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5179 if (G_UNLIKELY (!o))
5180 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5181 else if (G_UNLIKELY (vtable->klass->has_finalize))
5182 mono_object_register_finalizer (o);
5188 * mono_object_new_specific:
5189 * @vtable: the vtable of the object that we want to create
5191 * Returns: A newly created object with class and domain specified
5195 mono_object_new_specific (MonoVTable *vtable)
5198 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5199 mono_error_cleanup (&error);
5205 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5207 MONO_REQ_GC_UNSAFE_MODE;
5211 mono_error_init (error);
5213 /* check for is_com_object for COM Interop */
5214 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5217 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5220 MonoClass *klass = mono_class_get_activation_services_class ();
5223 mono_class_init (klass);
5225 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5227 mono_error_set_not_supported (error, "Linked away.");
5230 vtable->domain->create_proxy_for_type_method = im;
5233 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5234 if (!mono_error_ok (error))
5237 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5238 if (!mono_error_ok (error))
5245 return mono_object_new_alloc_specific_checked (vtable, error);
5249 ves_icall_object_new_specific (MonoVTable *vtable)
5252 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5253 mono_error_set_pending_exception (&error);
5259 * mono_object_new_alloc_specific:
5260 * @vtable: virtual table for the object.
5262 * This function allocates a new `MonoObject` with the type derived
5263 * from the @vtable information. If the class of this object has a
5264 * finalizer, then the object will be tracked for finalization.
5266 * This method might raise an exception on errors. Use the
5267 * `mono_object_new_fast_checked` method if you want to manually raise
5270 * Returns: the allocated object.
5273 mono_object_new_alloc_specific (MonoVTable *vtable)
5276 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5277 mono_error_cleanup (&error);
5283 * mono_object_new_alloc_specific_checked:
5284 * @vtable: virtual table for the object.
5285 * @error: holds the error return value.
5287 * This function allocates a new `MonoObject` with the type derived
5288 * from the @vtable information. If the class of this object has a
5289 * finalizer, then the object will be tracked for finalization.
5291 * If there is not enough memory, the @error parameter will be set
5292 * and will contain a user-visible message with the amount of bytes
5293 * that were requested.
5295 * Returns: the allocated object, or NULL if there is not enough memory
5299 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5301 MONO_REQ_GC_UNSAFE_MODE;
5305 mono_error_init (error);
5307 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5309 if (G_UNLIKELY (!o))
5310 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5311 else if (G_UNLIKELY (vtable->klass->has_finalize))
5312 mono_object_register_finalizer (o);
5318 * mono_object_new_fast:
5319 * @vtable: virtual table for the object.
5321 * This function allocates a new `MonoObject` with the type derived
5322 * from the @vtable information. The returned object is not tracked
5323 * for finalization. If your object implements a finalizer, you should
5324 * use `mono_object_new_alloc_specific` instead.
5326 * This method might raise an exception on errors. Use the
5327 * `mono_object_new_fast_checked` method if you want to manually raise
5330 * Returns: the allocated object.
5333 mono_object_new_fast (MonoVTable *vtable)
5336 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5337 mono_error_cleanup (&error);
5343 * mono_object_new_fast_checked:
5344 * @vtable: virtual table for the object.
5345 * @error: holds the error return value.
5347 * This function allocates a new `MonoObject` with the type derived
5348 * from the @vtable information. The returned object is not tracked
5349 * for finalization. If your object implements a finalizer, you should
5350 * use `mono_object_new_alloc_specific_checked` instead.
5352 * If there is not enough memory, the @error parameter will be set
5353 * and will contain a user-visible message with the amount of bytes
5354 * that were requested.
5356 * Returns: the allocated object, or NULL if there is not enough memory
5360 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5362 MONO_REQ_GC_UNSAFE_MODE;
5366 mono_error_init (error);
5368 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5370 if (G_UNLIKELY (!o))
5371 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5377 ves_icall_object_new_fast (MonoVTable *vtable)
5380 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5381 mono_error_set_pending_exception (&error);
5387 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5389 MONO_REQ_GC_UNSAFE_MODE;
5393 mono_error_init (error);
5395 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5397 if (G_UNLIKELY (!o))
5398 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5399 else if (G_UNLIKELY (vtable->klass->has_finalize))
5400 mono_object_register_finalizer (o);
5406 * mono_class_get_allocation_ftn:
5408 * @for_box: the object will be used for boxing
5409 * @pass_size_in_words:
5411 * Return the allocation function appropriate for the given class.
5415 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5417 MONO_REQ_GC_NEUTRAL_MODE;
5419 *pass_size_in_words = FALSE;
5421 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5422 return ves_icall_object_new_specific;
5424 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5426 return ves_icall_object_new_fast;
5429 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5430 * of the overhead of parameter passing.
5433 *pass_size_in_words = TRUE;
5434 #ifdef GC_REDIRECT_TO_LOCAL
5435 return GC_local_gcj_fast_malloc;
5437 return GC_gcj_fast_malloc;
5442 return ves_icall_object_new_specific;
5446 * mono_object_new_from_token:
5447 * @image: Context where the type_token is hosted
5448 * @token: a token of the type that we want to create
5450 * Returns: A newly created object whose definition is
5451 * looked up using @token in the @image image
5454 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5456 MONO_REQ_GC_UNSAFE_MODE;
5462 klass = mono_class_get_checked (image, token, &error);
5463 mono_error_assert_ok (&error);
5465 result = mono_object_new_checked (domain, klass, &error);
5467 mono_error_cleanup (&error);
5474 * mono_object_clone:
5475 * @obj: the object to clone
5477 * Returns: A newly created object who is a shallow copy of @obj
5480 mono_object_clone (MonoObject *obj)
5483 MonoObject *o = mono_object_clone_checked (obj, &error);
5484 mono_error_cleanup (&error);
5490 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5492 MONO_REQ_GC_UNSAFE_MODE;
5497 mono_error_init (error);
5499 size = obj->vtable->klass->instance_size;
5501 if (obj->vtable->klass->rank)
5502 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5504 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5506 if (G_UNLIKELY (!o)) {
5507 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5511 /* If the object doesn't contain references this will do a simple memmove. */
5512 mono_gc_wbarrier_object_copy (o, obj);
5514 if (obj->vtable->klass->has_finalize)
5515 mono_object_register_finalizer (o);
5520 * mono_array_full_copy:
5521 * @src: source array to copy
5522 * @dest: destination array
5524 * Copies the content of one array to another with exactly the same type and size.
5527 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5529 MONO_REQ_GC_UNSAFE_MODE;
5532 MonoClass *klass = src->obj.vtable->klass;
5534 g_assert (klass == dest->obj.vtable->klass);
5536 size = mono_array_length (src);
5537 g_assert (size == mono_array_length (dest));
5538 size *= mono_array_element_size (klass);
5540 if (klass->element_class->valuetype) {
5541 if (klass->element_class->has_references)
5542 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5544 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5546 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5549 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5554 * mono_array_clone_in_domain:
5555 * @domain: the domain in which the array will be cloned into
5556 * @array: the array to clone
5557 * @error: set on error
5559 * This routine returns a copy of the array that is hosted on the
5560 * specified MonoDomain. On failure returns NULL and sets @error.
5563 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5565 MONO_REQ_GC_UNSAFE_MODE;
5570 MonoClass *klass = array->obj.vtable->klass;
5572 mono_error_init (error);
5574 if (array->bounds == NULL) {
5575 size = mono_array_length (array);
5576 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5577 return_val_if_nok (error, NULL);
5579 size *= mono_array_element_size (klass);
5581 if (klass->element_class->valuetype) {
5582 if (klass->element_class->has_references)
5583 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5585 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5587 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5590 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5595 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5596 size = mono_array_element_size (klass);
5597 for (i = 0; i < klass->rank; ++i) {
5598 sizes [i] = array->bounds [i].length;
5599 size *= array->bounds [i].length;
5600 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5602 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5603 return_val_if_nok (error, NULL);
5605 if (klass->element_class->valuetype) {
5606 if (klass->element_class->has_references)
5607 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5609 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5611 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5614 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5622 * @array: the array to clone
5624 * Returns: A newly created array who is a shallow copy of @array
5627 mono_array_clone (MonoArray *array)
5629 MONO_REQ_GC_UNSAFE_MODE;
5632 MonoArray *result = mono_array_clone_checked (array, &error);
5633 mono_error_cleanup (&error);
5638 * mono_array_clone_checked:
5639 * @array: the array to clone
5640 * @error: set on error
5642 * Returns: A newly created array who is a shallow copy of @array. On
5643 * failure returns NULL and sets @error.
5646 mono_array_clone_checked (MonoArray *array, MonoError *error)
5649 MONO_REQ_GC_UNSAFE_MODE;
5650 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5653 /* helper macros to check for overflow when calculating the size of arrays */
5654 #ifdef MONO_BIG_ARRAYS
5655 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5656 #define MYGUINT_MAX MYGUINT64_MAX
5657 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5658 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5659 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5660 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5661 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5663 #define MYGUINT32_MAX 4294967295U
5664 #define MYGUINT_MAX MYGUINT32_MAX
5665 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5666 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5667 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5668 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5669 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5673 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5675 MONO_REQ_GC_NEUTRAL_MODE;
5679 byte_len = mono_array_element_size (klass);
5680 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5683 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5685 byte_len += MONO_SIZEOF_MONO_ARRAY;
5693 * mono_array_new_full:
5694 * @domain: domain where the object is created
5695 * @array_class: array class
5696 * @lengths: lengths for each dimension in the array
5697 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5699 * This routine creates a new array objects with the given dimensions,
5700 * lower bounds and type.
5703 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5706 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5707 mono_error_cleanup (&error);
5713 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5715 MONO_REQ_GC_UNSAFE_MODE;
5717 uintptr_t byte_len = 0, len, bounds_size;
5720 MonoArrayBounds *bounds;
5724 mono_error_init (error);
5726 if (!array_class->inited)
5727 mono_class_init (array_class);
5731 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5732 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5734 if (len > MONO_ARRAY_MAX_INDEX) {
5735 mono_error_set_generic_error (error, "System", "OverflowException", "");
5740 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5742 for (i = 0; i < array_class->rank; ++i) {
5743 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5744 mono_error_set_generic_error (error, "System", "OverflowException", "");
5747 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5748 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5755 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5756 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5762 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5763 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5766 byte_len = (byte_len + 3) & ~3;
5767 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5768 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5771 byte_len += bounds_size;
5774 * Following three lines almost taken from mono_object_new ():
5775 * they need to be kept in sync.
5777 vtable = mono_class_vtable_full (domain, array_class, error);
5778 return_val_if_nok (error, NULL);
5781 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5783 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5785 if (G_UNLIKELY (!o)) {
5786 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5790 array = (MonoArray*)o;
5792 bounds = array->bounds;
5795 for (i = 0; i < array_class->rank; ++i) {
5796 bounds [i].length = lengths [i];
5798 bounds [i].lower_bound = lower_bounds [i];
5807 * @domain: domain where the object is created
5808 * @eclass: element class
5809 * @n: number of array elements
5811 * This routine creates a new szarray with @n elements of type @eclass.
5814 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5816 MONO_REQ_GC_UNSAFE_MODE;
5819 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5820 mono_error_cleanup (&error);
5825 * mono_array_new_checked:
5826 * @domain: domain where the object is created
5827 * @eclass: element class
5828 * @n: number of array elements
5829 * @error: set on error
5831 * This routine creates a new szarray with @n elements of type @eclass.
5832 * On failure returns NULL and sets @error.
5835 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5839 mono_error_init (error);
5841 ac = mono_array_class_get (eclass, 1);
5844 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5845 return_val_if_nok (error, NULL);
5847 return mono_array_new_specific_checked (vtable, n, error);
5851 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5854 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5855 mono_error_set_pending_exception (&error);
5861 * mono_array_new_specific:
5862 * @vtable: a vtable in the appropriate domain for an initialized class
5863 * @n: number of array elements
5865 * This routine is a fast alternative to mono_array_new() for code which
5866 * can be sure about the domain it operates in.
5869 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5872 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5873 mono_error_cleanup (&error);
5879 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5881 MONO_REQ_GC_UNSAFE_MODE;
5886 mono_error_init (error);
5888 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5889 mono_error_set_generic_error (error, "System", "OverflowException", "");
5893 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5894 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5897 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5899 if (G_UNLIKELY (!o)) {
5900 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5904 return (MonoArray*)o;
5908 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5911 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5912 mono_error_set_pending_exception (&error);
5918 * mono_string_new_utf16:
5919 * @text: a pointer to an utf16 string
5920 * @len: the length of the string
5922 * Returns: A newly created string object which contains @text.
5925 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5927 MONO_REQ_GC_UNSAFE_MODE;
5930 MonoString *res = NULL;
5931 res = mono_string_new_utf16_checked (domain, text, len, &error);
5932 mono_error_cleanup (&error);
5938 * mono_string_new_utf16_checked:
5939 * @text: a pointer to an utf16 string
5940 * @len: the length of the string
5941 * @error: written on error.
5943 * Returns: A newly created string object which contains @text.
5944 * On error, returns NULL and sets @error.
5947 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5949 MONO_REQ_GC_UNSAFE_MODE;
5953 mono_error_init (error);
5955 s = mono_string_new_size_checked (domain, len, error);
5957 memcpy (mono_string_chars (s), text, len * 2);
5963 * mono_string_new_utf32:
5964 * @text: a pointer to an utf32 string
5965 * @len: the length of the string
5966 * @error: set on failure.
5968 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5971 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5973 MONO_REQ_GC_UNSAFE_MODE;
5976 mono_unichar2 *utf16_output = NULL;
5977 gint32 utf16_len = 0;
5978 GError *gerror = NULL;
5979 glong items_written;
5981 mono_error_init (error);
5982 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5985 g_error_free (gerror);
5987 while (utf16_output [utf16_len]) utf16_len++;
5989 s = mono_string_new_size_checked (domain, utf16_len, error);
5990 return_val_if_nok (error, NULL);
5992 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5994 g_free (utf16_output);
6000 * mono_string_new_utf32:
6001 * @text: a pointer to an utf32 string
6002 * @len: the length of the string
6004 * Returns: A newly created string object which contains @text.
6007 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6010 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6011 mono_error_cleanup (&error);
6016 * mono_string_new_size:
6017 * @text: a pointer to an utf16 string
6018 * @len: the length of the string
6020 * Returns: A newly created string object of @len
6023 mono_string_new_size (MonoDomain *domain, gint32 len)
6026 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6027 mono_error_cleanup (&error);
6033 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6035 MONO_REQ_GC_UNSAFE_MODE;
6041 mono_error_init (error);
6043 /* check for overflow */
6044 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6045 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6049 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6050 g_assert (size > 0);
6052 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6055 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6057 if (G_UNLIKELY (!s)) {
6058 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6066 * mono_string_new_len:
6067 * @text: a pointer to an utf8 string
6068 * @length: number of bytes in @text to consider
6070 * Returns: A newly created string object which contains @text.
6073 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6075 MONO_REQ_GC_UNSAFE_MODE;
6078 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6079 mono_error_cleanup (&error);
6084 * mono_string_new_len_checked:
6085 * @text: a pointer to an utf8 string
6086 * @length: number of bytes in @text to consider
6087 * @error: set on error
6089 * Returns: A newly created string object which contains @text. On
6090 * failure returns NULL and sets @error.
6093 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6095 MONO_REQ_GC_UNSAFE_MODE;
6097 mono_error_init (error);
6099 GError *eg_error = NULL;
6100 MonoString *o = NULL;
6102 glong items_written;
6104 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6107 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6109 g_error_free (eg_error);
6118 * @text: a pointer to an utf8 string
6120 * Returns: A newly created string object which contains @text.
6122 * This function asserts if it cannot allocate a new string.
6124 * @deprecated Use mono_string_new_checked in new code.
6127 mono_string_new (MonoDomain *domain, const char *text)
6130 MonoString *res = NULL;
6131 res = mono_string_new_checked (domain, text, &error);
6132 mono_error_assert_ok (&error);
6137 * mono_string_new_checked:
6138 * @text: a pointer to an utf8 string
6139 * @merror: set on error
6141 * Returns: A newly created string object which contains @text.
6142 * On error returns NULL and sets @merror.
6145 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6147 MONO_REQ_GC_UNSAFE_MODE;
6149 GError *eg_error = NULL;
6150 MonoString *o = NULL;
6152 glong items_written;
6155 mono_error_init (error);
6159 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6162 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6164 g_error_free (eg_error);
6168 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6173 MonoString *o = NULL;
6175 if (!g_utf8_validate (text, -1, &end)) {
6176 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6180 len = g_utf8_strlen (text, -1);
6181 o = mono_string_new_size_checked (domain, len, error);
6184 str = mono_string_chars (o);
6186 while (text < end) {
6187 *str++ = g_utf8_get_char (text);
6188 text = g_utf8_next_char (text);
6197 * mono_string_new_wrapper:
6198 * @text: pointer to utf8 characters.
6200 * Helper function to create a string object from @text in the current domain.
6203 mono_string_new_wrapper (const char *text)
6205 MONO_REQ_GC_UNSAFE_MODE;
6207 MonoDomain *domain = mono_domain_get ();
6210 return mono_string_new (domain, text);
6217 * @class: the class of the value
6218 * @value: a pointer to the unboxed data
6220 * Returns: A newly created object which contains @value.
6223 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6226 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6227 mono_error_cleanup (&error);
6232 * mono_value_box_checked:
6233 * @domain: the domain of the new object
6234 * @class: the class of the value
6235 * @value: a pointer to the unboxed data
6236 * @error: set on error
6238 * Returns: A newly created object which contains @value. On failure
6239 * returns NULL and sets @error.
6242 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6244 MONO_REQ_GC_UNSAFE_MODE;
6249 mono_error_init (error);
6251 g_assert (klass->valuetype);
6252 if (mono_class_is_nullable (klass))
6253 return mono_nullable_box ((guint8 *)value, klass, error);
6255 vtable = mono_class_vtable (domain, klass);
6258 size = mono_class_instance_size (klass);
6259 res = mono_object_new_alloc_specific_checked (vtable, error);
6260 return_val_if_nok (error, NULL);
6262 size = size - sizeof (MonoObject);
6265 g_assert (size == mono_class_value_size (klass, NULL));
6266 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6268 #if NO_UNALIGNED_ACCESS
6269 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6273 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6276 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6279 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6282 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6285 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6289 if (klass->has_finalize) {
6290 mono_object_register_finalizer (res);
6291 return_val_if_nok (error, NULL);
6298 * @dest: destination pointer
6299 * @src: source pointer
6300 * @klass: a valuetype class
6302 * Copy a valuetype from @src to @dest. This function must be used
6303 * when @klass contains references fields.
6306 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6308 MONO_REQ_GC_UNSAFE_MODE;
6310 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6314 * mono_value_copy_array:
6315 * @dest: destination array
6316 * @dest_idx: index in the @dest array
6317 * @src: source pointer
6318 * @count: number of items
6320 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6321 * This function must be used when @klass contains references fields.
6322 * Overlap is handled.
6325 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6327 MONO_REQ_GC_UNSAFE_MODE;
6329 int size = mono_array_element_size (dest->obj.vtable->klass);
6330 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6331 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6332 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6336 * mono_object_get_domain:
6337 * @obj: object to query
6339 * Returns: the MonoDomain where the object is hosted
6342 mono_object_get_domain (MonoObject *obj)
6344 MONO_REQ_GC_UNSAFE_MODE;
6346 return mono_object_domain (obj);
6350 * mono_object_get_class:
6351 * @obj: object to query
6353 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6355 * Returns: the MonoClass of the object.
6358 mono_object_get_class (MonoObject *obj)
6360 MONO_REQ_GC_UNSAFE_MODE;
6362 return mono_object_class (obj);
6365 * mono_object_get_size:
6366 * @o: object to query
6368 * Returns: the size, in bytes, of @o
6371 mono_object_get_size (MonoObject* o)
6373 MONO_REQ_GC_UNSAFE_MODE;
6375 MonoClass* klass = mono_object_class (o);
6376 if (klass == mono_defaults.string_class) {
6377 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6378 } else if (o->vtable->rank) {
6379 MonoArray *array = (MonoArray*)o;
6380 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6381 if (array->bounds) {
6384 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6388 return mono_class_instance_size (klass);
6393 * mono_object_unbox:
6394 * @obj: object to unbox
6396 * Returns: a pointer to the start of the valuetype boxed in this
6399 * This method will assert if the object passed is not a valuetype.
6402 mono_object_unbox (MonoObject *obj)
6404 MONO_REQ_GC_UNSAFE_MODE;
6406 /* add assert for valuetypes? */
6407 g_assert (obj->vtable->klass->valuetype);
6408 return ((char*)obj) + sizeof (MonoObject);
6412 * mono_object_isinst:
6414 * @klass: a pointer to a class
6416 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6419 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6421 MONO_REQ_GC_UNSAFE_MODE;
6424 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6425 mono_error_cleanup (&error);
6431 * mono_object_isinst_checked:
6433 * @klass: a pointer to a class
6434 * @error: set on error
6436 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6437 * On failure returns NULL and sets @error.
6440 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6442 MONO_REQ_GC_UNSAFE_MODE;
6444 mono_error_init (error);
6446 MonoObject *result = NULL;
6449 mono_class_init (klass);
6451 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6452 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6459 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6463 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6465 MONO_REQ_GC_UNSAFE_MODE;
6468 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6469 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6474 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6476 MONO_REQ_GC_UNSAFE_MODE;
6480 mono_error_init (error);
6487 if (mono_class_is_interface (klass)) {
6488 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6492 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6493 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6496 MonoClass *oklass = vt->klass;
6497 if (mono_class_is_transparent_proxy (oklass))
6498 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6500 mono_class_setup_supertypes (klass);
6501 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6504 #ifndef DISABLE_REMOTING
6505 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6507 MonoDomain *domain = mono_domain_get ();
6509 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6510 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6511 MonoMethod *im = NULL;
6514 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6516 mono_error_set_not_supported (error, "Linked away.");
6519 im = mono_object_get_virtual_method (rp, im);
6522 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6523 return_val_if_nok (error, NULL);
6526 res = mono_runtime_invoke_checked (im, rp, pa, error);
6527 return_val_if_nok (error, NULL);
6529 if (*(MonoBoolean *) mono_object_unbox(res)) {
6530 /* Update the vtable of the remote type, so it can safely cast to this new type */
6531 mono_upgrade_remote_class (domain, obj, klass, error);
6532 return_val_if_nok (error, NULL);
6536 #endif /* DISABLE_REMOTING */
6541 * mono_object_castclass_mbyref:
6543 * @klass: a pointer to a class
6545 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6548 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6550 MONO_REQ_GC_UNSAFE_MODE;
6553 if (!obj) return NULL;
6554 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6555 mono_error_cleanup (&error);
6560 MonoDomain *orig_domain;
6566 str_lookup (MonoDomain *domain, gpointer user_data)
6568 MONO_REQ_GC_UNSAFE_MODE;
6570 LDStrInfo *info = (LDStrInfo *)user_data;
6571 if (info->res || domain == info->orig_domain)
6573 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6577 mono_string_get_pinned (MonoString *str, MonoError *error)
6579 MONO_REQ_GC_UNSAFE_MODE;
6581 mono_error_init (error);
6583 /* We only need to make a pinned version of a string if this is a moving GC */
6584 if (!mono_gc_is_moving ())
6588 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6589 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6591 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6592 news->length = mono_string_length (str);
6594 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6600 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6602 MONO_REQ_GC_UNSAFE_MODE;
6604 MonoGHashTable *ldstr_table;
6605 MonoString *s, *res;
6608 mono_error_init (error);
6610 domain = ((MonoObject *)str)->vtable->domain;
6611 ldstr_table = domain->ldstr_table;
6613 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6619 /* Allocate outside the lock */
6621 s = mono_string_get_pinned (str, error);
6622 return_val_if_nok (error, NULL);
6625 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6630 mono_g_hash_table_insert (ldstr_table, s, s);
6635 LDStrInfo ldstr_info;
6636 ldstr_info.orig_domain = domain;
6637 ldstr_info.ins = str;
6638 ldstr_info.res = NULL;
6640 mono_domain_foreach (str_lookup, &ldstr_info);
6641 if (ldstr_info.res) {
6643 * the string was already interned in some other domain:
6644 * intern it in the current one as well.
6646 mono_g_hash_table_insert (ldstr_table, str, str);
6656 * mono_string_is_interned:
6657 * @o: String to probe
6659 * Returns whether the string has been interned.
6662 mono_string_is_interned (MonoString *o)
6665 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6666 /* This function does not fail. */
6667 mono_error_assert_ok (&error);
6672 * mono_string_intern:
6673 * @o: String to intern
6675 * Interns the string passed.
6676 * Returns: The interned string.
6679 mono_string_intern (MonoString *str)
6682 MonoString *result = mono_string_intern_checked (str, &error);
6683 mono_error_assert_ok (&error);
6688 * mono_string_intern_checked:
6689 * @o: String to intern
6690 * @error: set on error.
6692 * Interns the string passed.
6693 * Returns: The interned string. On failure returns NULL and sets @error
6696 mono_string_intern_checked (MonoString *str, MonoError *error)
6698 MONO_REQ_GC_UNSAFE_MODE;
6700 mono_error_init (error);
6702 return mono_string_is_interned_lookup (str, TRUE, error);
6707 * @domain: the domain where the string will be used.
6708 * @image: a metadata context
6709 * @idx: index into the user string table.
6711 * Implementation for the ldstr opcode.
6712 * Returns: a loaded string from the @image/@idx combination.
6715 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6718 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6719 mono_error_cleanup (&error);
6724 * mono_ldstr_checked:
6725 * @domain: the domain where the string will be used.
6726 * @image: a metadata context
6727 * @idx: index into the user string table.
6728 * @error: set on error.
6730 * Implementation for the ldstr opcode.
6731 * Returns: a loaded string from the @image/@idx combination.
6732 * On failure returns NULL and sets @error.
6735 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6737 MONO_REQ_GC_UNSAFE_MODE;
6738 mono_error_init (error);
6740 if (image->dynamic) {
6741 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6744 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6745 return NULL; /*FIXME we should probably be raising an exception here*/
6746 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6752 * mono_ldstr_metadata_sig
6753 * @domain: the domain for the string
6754 * @sig: the signature of a metadata string
6755 * @error: set on error
6757 * Returns: a MonoString for a string stored in the metadata. On
6758 * failure returns NULL and sets @error.
6761 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6763 MONO_REQ_GC_UNSAFE_MODE;
6765 mono_error_init (error);
6766 const char *str = sig;
6767 MonoString *o, *interned;
6770 len2 = mono_metadata_decode_blob_size (str, &str);
6773 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6774 return_val_if_nok (error, NULL);
6775 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6778 guint16 *p2 = (guint16*)mono_string_chars (o);
6779 for (i = 0; i < len2; ++i) {
6780 *p2 = GUINT16_FROM_LE (*p2);
6786 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6789 return interned; /* o will get garbage collected */
6791 o = mono_string_get_pinned (o, error);
6794 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6796 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6808 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6812 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6818 GError *gerror = NULL;
6820 mono_error_init (error);
6822 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6823 return NULL; /*FIXME we should probably be raising an exception here*/
6824 str = mono_metadata_user_string (image, idx);
6826 len2 = mono_metadata_decode_blob_size (str, &str);
6829 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6831 mono_error_set_argument (error, "string", "%s", gerror->message);
6832 g_error_free (gerror);
6835 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6836 if (len2 > written) {
6837 /* allocate the total length and copy the part of the string that has been converted */
6838 char *as2 = (char *)g_malloc0 (len2);
6839 memcpy (as2, as, written);
6848 * mono_string_to_utf8:
6849 * @s: a System.String
6851 * Returns the UTF8 representation for @s.
6852 * The resulting buffer needs to be freed with mono_free().
6854 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6857 mono_string_to_utf8 (MonoString *s)
6859 MONO_REQ_GC_UNSAFE_MODE;
6862 char *result = mono_string_to_utf8_checked (s, &error);
6864 if (!is_ok (&error)) {
6865 mono_error_cleanup (&error);
6872 * mono_string_to_utf8_checked:
6873 * @s: a System.String
6874 * @error: a MonoError.
6876 * Converts a MonoString to its UTF8 representation. May fail; check
6877 * @error to determine whether the conversion was successful.
6878 * The resulting buffer should be freed with mono_free().
6881 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6883 MONO_REQ_GC_UNSAFE_MODE;
6887 GError *gerror = NULL;
6889 mono_error_init (error);
6895 return g_strdup ("");
6897 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6899 mono_error_set_argument (error, "string", "%s", gerror->message);
6900 g_error_free (gerror);
6903 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6904 if (s->length > written) {
6905 /* allocate the total length and copy the part of the string that has been converted */
6906 char *as2 = (char *)g_malloc0 (s->length);
6907 memcpy (as2, as, written);
6916 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6918 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6922 * mono_string_to_utf8_ignore:
6925 * Converts a MonoString to its UTF8 representation. Will ignore
6926 * invalid surrogate pairs.
6927 * The resulting buffer should be freed with mono_free().
6931 mono_string_to_utf8_ignore (MonoString *s)
6933 MONO_REQ_GC_UNSAFE_MODE;
6942 return g_strdup ("");
6944 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6946 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6947 if (s->length > written) {
6948 /* allocate the total length and copy the part of the string that has been converted */
6949 char *as2 = (char *)g_malloc0 (s->length);
6950 memcpy (as2, as, written);
6959 * mono_string_to_utf8_image_ignore:
6960 * @s: a System.String
6962 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6965 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6967 MONO_REQ_GC_UNSAFE_MODE;
6969 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6973 * mono_string_to_utf8_mp_ignore:
6974 * @s: a System.String
6976 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6979 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6981 MONO_REQ_GC_UNSAFE_MODE;
6983 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6988 * mono_string_to_utf16:
6991 * Return an null-terminated array of the utf-16 chars
6992 * contained in @s. The result must be freed with g_free().
6993 * This is a temporary helper until our string implementation
6994 * is reworked to always include the null terminating char.
6997 mono_string_to_utf16 (MonoString *s)
6999 MONO_REQ_GC_UNSAFE_MODE;
7006 as = (char *)g_malloc ((s->length * 2) + 2);
7007 as [(s->length * 2)] = '\0';
7008 as [(s->length * 2) + 1] = '\0';
7011 return (gunichar2 *)(as);
7014 memcpy (as, mono_string_chars(s), s->length * 2);
7015 return (gunichar2 *)(as);
7019 * mono_string_to_utf32:
7022 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7023 * contained in @s. The result must be freed with g_free().
7026 mono_string_to_utf32 (MonoString *s)
7028 MONO_REQ_GC_UNSAFE_MODE;
7030 mono_unichar4 *utf32_output = NULL;
7031 GError *error = NULL;
7032 glong items_written;
7037 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7040 g_error_free (error);
7042 return utf32_output;
7046 * mono_string_from_utf16:
7047 * @data: the UTF16 string (LPWSTR) to convert
7049 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7051 * Returns: a MonoString.
7054 mono_string_from_utf16 (gunichar2 *data)
7057 MonoString *result = mono_string_from_utf16_checked (data, &error);
7058 mono_error_cleanup (&error);
7063 * mono_string_from_utf16_checked:
7064 * @data: the UTF16 string (LPWSTR) to convert
7065 * @error: set on error
7067 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7069 * Returns: a MonoString. On failure sets @error and returns NULL.
7072 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7075 MONO_REQ_GC_UNSAFE_MODE;
7077 mono_error_init (error);
7078 MonoDomain *domain = mono_domain_get ();
7084 while (data [len]) len++;
7086 return mono_string_new_utf16_checked (domain, data, len, error);
7090 * mono_string_from_utf32:
7091 * @data: the UTF32 string (LPWSTR) to convert
7093 * Converts a UTF32 (UCS-4)to a MonoString.
7095 * Returns: a MonoString.
7098 mono_string_from_utf32 (mono_unichar4 *data)
7101 MonoString *result = mono_string_from_utf32_checked (data, &error);
7102 mono_error_cleanup (&error);
7107 * mono_string_from_utf32_checked:
7108 * @data: the UTF32 string (LPWSTR) to convert
7109 * @error: set on error
7111 * Converts a UTF32 (UCS-4)to a MonoString.
7113 * Returns: a MonoString. On failure returns NULL and sets @error.
7116 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7118 MONO_REQ_GC_UNSAFE_MODE;
7120 mono_error_init (error);
7121 MonoString* result = NULL;
7122 mono_unichar2 *utf16_output = NULL;
7123 GError *gerror = NULL;
7124 glong items_written;
7130 while (data [len]) len++;
7132 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7135 g_error_free (gerror);
7137 result = mono_string_from_utf16_checked (utf16_output, error);
7138 g_free (utf16_output);
7143 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7145 MONO_REQ_GC_UNSAFE_MODE;
7152 r = mono_string_to_utf8_ignore (s);
7154 r = mono_string_to_utf8_checked (s, error);
7155 if (!mono_error_ok (error))
7162 len = strlen (r) + 1;
7164 mp_s = (char *)mono_mempool_alloc (mp, len);
7166 mp_s = (char *)mono_image_alloc (image, len);
7168 memcpy (mp_s, r, len);
7176 * mono_string_to_utf8_image:
7177 * @s: a System.String
7179 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7182 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7184 MONO_REQ_GC_UNSAFE_MODE;
7186 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7190 * mono_string_to_utf8_mp:
7191 * @s: a System.String
7193 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7196 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7198 MONO_REQ_GC_UNSAFE_MODE;
7200 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7204 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7207 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7209 eh_callbacks = *cbs;
7212 MonoRuntimeExceptionHandlingCallbacks *
7213 mono_get_eh_callbacks (void)
7215 return &eh_callbacks;
7219 * mono_raise_exception:
7220 * @ex: exception object
7222 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7225 mono_raise_exception (MonoException *ex)
7227 MONO_REQ_GC_UNSAFE_MODE;
7230 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7231 * that will cause gcc to omit the function epilog, causing problems when
7232 * the JIT tries to walk the stack, since the return address on the stack
7233 * will point into the next function in the executable, not this one.
7235 eh_callbacks.mono_raise_exception (ex);
7239 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7241 MONO_REQ_GC_UNSAFE_MODE;
7243 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7247 * mono_wait_handle_new:
7248 * @domain: Domain where the object will be created
7249 * @handle: Handle for the wait handle
7250 * @error: set on error.
7252 * Returns: A new MonoWaitHandle created in the given domain for the
7253 * given handle. On failure returns NULL and sets @rror.
7256 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7258 MONO_REQ_GC_UNSAFE_MODE;
7260 MonoWaitHandle *res;
7261 gpointer params [1];
7262 static MonoMethod *handle_set;
7264 mono_error_init (error);
7265 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7266 return_val_if_nok (error, NULL);
7268 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7270 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7272 params [0] = &handle;
7274 mono_runtime_invoke_checked (handle_set, res, params, error);
7279 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7281 MONO_REQ_GC_UNSAFE_MODE;
7283 static MonoClassField *f_safe_handle = NULL;
7286 if (!f_safe_handle) {
7287 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7288 g_assert (f_safe_handle);
7291 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7297 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7299 MONO_REQ_GC_UNSAFE_MODE;
7301 RuntimeInvokeFunction runtime_invoke;
7303 mono_error_init (error);
7305 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7306 MonoMethod *method = mono_get_context_capture_method ();
7307 MonoMethod *wrapper;
7310 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7311 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7312 return_val_if_nok (error, NULL);
7313 domain->capture_context_method = mono_compile_method_checked (method, error);
7314 return_val_if_nok (error, NULL);
7317 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7319 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7322 * mono_async_result_new:
7323 * @domain:domain where the object will be created.
7324 * @handle: wait handle.
7325 * @state: state to pass to AsyncResult
7326 * @data: C closure data.
7327 * @error: set on error.
7329 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7330 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7331 * On failure returns NULL and sets @error.
7335 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7337 MONO_REQ_GC_UNSAFE_MODE;
7339 mono_error_init (error);
7340 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7341 return_val_if_nok (error, NULL);
7342 MonoObject *context = mono_runtime_capture_context (domain, error);
7343 return_val_if_nok (error, NULL);
7344 /* we must capture the execution context from the original thread */
7346 MONO_OBJECT_SETREF (res, execution_context, context);
7347 /* note: result may be null if the flow is suppressed */
7350 res->data = (void **)data;
7351 MONO_OBJECT_SETREF (res, object_data, object_data);
7352 MONO_OBJECT_SETREF (res, async_state, state);
7353 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7354 return_val_if_nok (error, NULL);
7356 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7358 res->sync_completed = FALSE;
7359 res->completed = FALSE;
7365 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7367 MONO_REQ_GC_UNSAFE_MODE;
7374 g_assert (ares->async_delegate);
7376 ac = (MonoAsyncCall*) ares->object_data;
7378 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7379 if (mono_error_set_pending_exception (&error))
7382 gpointer wait_event = NULL;
7384 ac->msg->exc = NULL;
7386 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7388 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7389 mono_threads_begin_abort_protected_block ();
7391 if (!ac->msg->exc) {
7392 MonoException *ex = mono_error_convert_to_exception (&error);
7393 ac->msg->exc = (MonoObject *)ex;
7395 mono_error_cleanup (&error);
7398 MONO_OBJECT_SETREF (ac, res, res);
7400 mono_monitor_enter ((MonoObject*) ares);
7401 ares->completed = 1;
7403 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7404 mono_monitor_exit ((MonoObject*) ares);
7406 if (wait_event != NULL)
7407 mono_w32event_set (wait_event);
7409 mono_error_init (&error); //the else branch would leave it in an undefined state
7411 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7413 mono_threads_end_abort_protected_block ();
7415 if (mono_error_set_pending_exception (&error))
7423 mono_message_init (MonoDomain *domain,
7424 MonoMethodMessage *this_obj,
7425 MonoReflectionMethod *method,
7426 MonoArray *out_args,
7429 MONO_REQ_GC_UNSAFE_MODE;
7431 static MonoMethod *init_message_method = NULL;
7433 if (!init_message_method) {
7434 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7435 g_assert (init_message_method != NULL);
7438 mono_error_init (error);
7439 /* FIXME set domain instead? */
7440 g_assert (domain == mono_domain_get ());
7447 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7448 return is_ok (error);
7451 #ifndef DISABLE_REMOTING
7453 * mono_remoting_invoke:
7454 * @real_proxy: pointer to a RealProxy object
7455 * @msg: The MonoMethodMessage to execute
7456 * @exc: used to store exceptions
7457 * @out_args: used to store output arguments
7459 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7460 * IMessage interface and it is not trivial to extract results from there. So
7461 * we call an helper method PrivateInvoke instead of calling
7462 * RealProxy::Invoke() directly.
7464 * Returns: the result object.
7467 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7469 MONO_REQ_GC_UNSAFE_MODE;
7472 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7477 mono_error_init (error);
7479 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7482 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7484 mono_error_set_not_supported (error, "Linked away.");
7487 real_proxy->vtable->domain->private_invoke_method = im;
7490 pa [0] = real_proxy;
7495 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7496 return_val_if_nok (error, NULL);
7503 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7504 MonoObject **exc, MonoArray **out_args, MonoError *error)
7506 MONO_REQ_GC_UNSAFE_MODE;
7508 static MonoClass *object_array_klass;
7509 mono_error_init (error);
7513 MonoMethodSignature *sig;
7515 int i, j, outarg_count = 0;
7517 #ifndef DISABLE_REMOTING
7518 if (target && mono_object_is_transparent_proxy (target)) {
7519 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7520 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7521 target = tp->rp->unwrapped_server;
7523 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7528 domain = mono_domain_get ();
7529 method = msg->method->method;
7530 sig = mono_method_signature (method);
7532 for (i = 0; i < sig->param_count; i++) {
7533 if (sig->params [i]->byref)
7537 if (!object_array_klass) {
7540 klass = mono_array_class_get (mono_defaults.object_class, 1);
7543 mono_memory_barrier ();
7544 object_array_klass = klass;
7547 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7548 return_val_if_nok (error, NULL);
7550 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7553 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7554 return_val_if_nok (error, NULL);
7556 for (i = 0, j = 0; i < sig->param_count; i++) {
7557 if (sig->params [i]->byref) {
7559 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7560 mono_array_setref (*out_args, j, arg);
7569 * prepare_to_string_method:
7571 * @target: Set to @obj or unboxed value if a valuetype
7573 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7576 prepare_to_string_method (MonoObject *obj, void **target)
7578 MONO_REQ_GC_UNSAFE_MODE;
7580 static MonoMethod *to_string = NULL;
7588 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7590 method = mono_object_get_virtual_method (obj, to_string);
7592 // Unbox value type if needed
7593 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7594 *target = mono_object_unbox (obj);
7600 * mono_object_to_string:
7602 * @exc: Any exception thrown by ToString (). May be NULL.
7604 * Returns: the result of calling ToString () on an object.
7607 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7610 MonoString *s = NULL;
7612 MonoMethod *method = prepare_to_string_method (obj, &target);
7614 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7615 if (*exc == NULL && !mono_error_ok (&error))
7616 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7618 mono_error_cleanup (&error);
7620 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7621 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7628 * mono_object_to_string_checked:
7630 * @error: Set on error.
7632 * Returns: the result of calling ToString () on an object. If the
7633 * method cannot be invoked or if it raises an exception, sets @error
7637 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7639 mono_error_init (error);
7641 MonoMethod *method = prepare_to_string_method (obj, &target);
7642 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7646 * mono_object_try_to_string:
7648 * @exc: Any exception thrown by ToString (). Must not be NULL.
7649 * @error: Set if method cannot be invoked.
7651 * Returns: the result of calling ToString () on an object. If the
7652 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7656 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7659 mono_error_init (error);
7661 MonoMethod *method = prepare_to_string_method (obj, &target);
7662 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7668 get_native_backtrace (MonoException *exc_raw)
7670 HANDLE_FUNCTION_ENTER ();
7671 MONO_HANDLE_DCL(MonoException, exc);
7672 char * trace = mono_exception_handle_get_native_backtrace (exc);
7673 HANDLE_FUNCTION_RETURN_VAL (trace);
7677 * mono_print_unhandled_exception:
7678 * @exc: The exception
7680 * Prints the unhandled exception.
7683 mono_print_unhandled_exception (MonoObject *exc)
7685 MONO_REQ_GC_UNSAFE_MODE;
7688 char *message = (char*)"";
7689 gboolean free_message = FALSE;
7692 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7693 message = g_strdup ("OutOfMemoryException");
7694 free_message = TRUE;
7695 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7696 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7697 free_message = TRUE;
7700 if (((MonoException*)exc)->native_trace_ips) {
7701 message = get_native_backtrace ((MonoException*)exc);
7702 free_message = TRUE;
7704 MonoObject *other_exc = NULL;
7705 str = mono_object_try_to_string (exc, &other_exc, &error);
7706 if (other_exc == NULL && !is_ok (&error))
7707 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7709 mono_error_cleanup (&error);
7711 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7712 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7714 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7715 original_backtrace, nested_backtrace);
7717 g_free (original_backtrace);
7718 g_free (nested_backtrace);
7719 free_message = TRUE;
7721 message = mono_string_to_utf8_checked (str, &error);
7722 if (!mono_error_ok (&error)) {
7723 mono_error_cleanup (&error);
7724 message = (char *) "";
7726 free_message = TRUE;
7733 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7734 * exc->vtable->klass->name, message);
7736 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7743 * mono_delegate_ctor_with_method:
7744 * @this: pointer to an uninitialized delegate object
7745 * @target: target object
7746 * @addr: pointer to native code
7748 * @error: set on error.
7750 * Initialize a delegate and sets a specific method, not the one
7751 * associated with addr. This is useful when sharing generic code.
7752 * In that case addr will most probably not be associated with the
7753 * correct instantiation of the method.
7754 * On failure returns FALSE and sets @error.
7757 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7759 MONO_REQ_GC_UNSAFE_MODE;
7761 mono_error_init (error);
7762 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7764 g_assert (this_obj);
7767 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7770 delegate->method = method;
7772 mono_stats.delegate_creations++;
7774 #ifndef DISABLE_REMOTING
7775 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7777 method = mono_marshal_get_remoting_invoke (method);
7778 delegate->method_ptr = mono_compile_method_checked (method, error);
7779 return_val_if_nok (error, FALSE);
7780 MONO_OBJECT_SETREF (delegate, target, target);
7784 delegate->method_ptr = addr;
7785 MONO_OBJECT_SETREF (delegate, target, target);
7788 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7789 if (callbacks.init_delegate)
7790 callbacks.init_delegate (delegate);
7795 * mono_delegate_ctor:
7796 * @this: pointer to an uninitialized delegate object
7797 * @target: target object
7798 * @addr: pointer to native code
7799 * @error: set on error.
7801 * This is used to initialize a delegate.
7802 * On failure returns FALSE and sets @error.
7805 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7807 MONO_REQ_GC_UNSAFE_MODE;
7809 mono_error_init (error);
7810 MonoDomain *domain = mono_domain_get ();
7812 MonoMethod *method = NULL;
7816 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7818 if (!ji && domain != mono_get_root_domain ())
7819 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7821 method = mono_jit_info_get_method (ji);
7822 g_assert (!mono_class_is_gtd (method->klass));
7825 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7829 * mono_method_call_message_new:
7830 * @method: method to encapsulate
7831 * @params: parameters to the method
7832 * @invoke: optional, delegate invoke.
7833 * @cb: async callback delegate.
7834 * @state: state passed to the async callback.
7835 * @error: set on error.
7837 * Translates arguments pointers into a MonoMethodMessage.
7838 * On failure returns NULL and sets @error.
7841 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7842 MonoDelegate **cb, MonoObject **state, MonoError *error)
7844 MONO_REQ_GC_UNSAFE_MODE;
7846 mono_error_init (error);
7848 MonoDomain *domain = mono_domain_get ();
7849 MonoMethodSignature *sig = mono_method_signature (method);
7850 MonoMethodMessage *msg;
7853 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7854 return_val_if_nok (error, NULL);
7857 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7858 return_val_if_nok (error, NULL);
7859 mono_message_init (domain, msg, rm, NULL, error);
7860 return_val_if_nok (error, NULL);
7861 count = sig->param_count - 2;
7863 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7864 return_val_if_nok (error, NULL);
7865 mono_message_init (domain, msg, rm, NULL, error);
7866 return_val_if_nok (error, NULL);
7867 count = sig->param_count;
7870 for (i = 0; i < count; i++) {
7875 if (sig->params [i]->byref)
7876 vpos = *((gpointer *)params [i]);
7880 klass = mono_class_from_mono_type (sig->params [i]);
7882 if (klass->valuetype) {
7883 arg = mono_value_box_checked (domain, klass, vpos, error);
7884 return_val_if_nok (error, NULL);
7886 arg = *((MonoObject **)vpos);
7888 mono_array_setref (msg->args, i, arg);
7891 if (cb != NULL && state != NULL) {
7892 *cb = *((MonoDelegate **)params [i]);
7894 *state = *((MonoObject **)params [i]);
7901 * mono_method_return_message_restore:
7903 * Restore results from message based processing back to arguments pointers
7906 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7908 MONO_REQ_GC_UNSAFE_MODE;
7910 mono_error_init (error);
7912 MonoMethodSignature *sig = mono_method_signature (method);
7913 int i, j, type, size, out_len;
7915 if (out_args == NULL)
7917 out_len = mono_array_length (out_args);
7921 for (i = 0, j = 0; i < sig->param_count; i++) {
7922 MonoType *pt = sig->params [i];
7927 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7931 arg = (char *)mono_array_get (out_args, gpointer, j);
7934 g_assert (type != MONO_TYPE_VOID);
7936 if (MONO_TYPE_IS_REFERENCE (pt)) {
7937 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7940 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7941 size = mono_class_value_size (klass, NULL);
7942 if (klass->has_references)
7943 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7945 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7947 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7948 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7957 #ifndef DISABLE_REMOTING
7960 * mono_load_remote_field:
7961 * @this: pointer to an object
7962 * @klass: klass of the object containing @field
7963 * @field: the field to load
7964 * @res: a storage to store the result
7966 * This method is called by the runtime on attempts to load fields of
7967 * transparent proxy objects. @this points to such TP, @klass is the class of
7968 * the object containing @field. @res is a storage location which can be
7969 * used to store the result.
7971 * Returns: an address pointing to the value of field.
7974 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7977 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7978 mono_error_cleanup (&error);
7983 * mono_load_remote_field_checked:
7984 * @this: pointer to an object
7985 * @klass: klass of the object containing @field
7986 * @field: the field to load
7987 * @res: a storage to store the result
7988 * @error: set on error
7990 * This method is called by the runtime on attempts to load fields of
7991 * transparent proxy objects. @this points to such TP, @klass is the class of
7992 * the object containing @field. @res is a storage location which can be
7993 * used to store the result.
7995 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
7998 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8000 MONO_REQ_GC_UNSAFE_MODE;
8002 static MonoMethod *getter = NULL;
8004 mono_error_init (error);
8006 MonoDomain *domain = mono_domain_get ();
8007 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8008 MonoClass *field_class;
8009 MonoMethodMessage *msg;
8010 MonoArray *out_args;
8014 g_assert (mono_object_is_transparent_proxy (this_obj));
8015 g_assert (res != NULL);
8017 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8018 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8023 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8025 mono_error_set_not_supported (error, "Linked away.");
8030 field_class = mono_class_from_mono_type (field->type);
8032 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8033 return_val_if_nok (error, NULL);
8034 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8035 return_val_if_nok (error, NULL);
8036 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8037 return_val_if_nok (error, NULL);
8038 mono_message_init (domain, msg, rm, out_args, error);
8039 return_val_if_nok (error, NULL);
8041 full_name = mono_type_get_full_name (klass);
8042 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8043 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8046 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8047 return_val_if_nok (error, NULL);
8050 mono_error_set_exception_instance (error, (MonoException *)exc);
8054 if (mono_array_length (out_args) == 0)
8057 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8059 if (field_class->valuetype) {
8060 return ((char *)*res) + sizeof (MonoObject);
8066 * mono_load_remote_field_new:
8071 * Missing documentation.
8074 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8078 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8079 mono_error_cleanup (&error);
8084 * mono_load_remote_field_new_checked:
8085 * @this: pointer to an object
8086 * @klass: klass of the object containing @field
8087 * @field: the field to load
8088 * @error: set on error.
8090 * This method is called by the runtime on attempts to load fields of
8091 * transparent proxy objects. @this points to such TP, @klass is the class of
8092 * the object containing @field.
8094 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8097 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8099 MONO_REQ_GC_UNSAFE_MODE;
8101 mono_error_init (error);
8103 static MonoMethod *tp_load = NULL;
8105 g_assert (mono_object_is_transparent_proxy (this_obj));
8108 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8110 mono_error_set_not_supported (error, "Linked away.");
8115 /* MonoType *type = mono_class_get_type (klass); */
8121 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8125 * mono_store_remote_field:
8126 * @this_obj: pointer to an object
8127 * @klass: klass of the object containing @field
8128 * @field: the field to load
8129 * @val: the value/object to store
8131 * This method is called by the runtime on attempts to store fields of
8132 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8133 * the object containing @field. @val is the new value to store in @field.
8136 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8139 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8140 mono_error_cleanup (&error);
8144 * mono_store_remote_field_checked:
8145 * @this_obj: pointer to an object
8146 * @klass: klass of the object containing @field
8147 * @field: the field to load
8148 * @val: the value/object to store
8149 * @error: set on error
8151 * This method is called by the runtime on attempts to store fields of
8152 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8153 * the object containing @field. @val is the new value to store in @field.
8155 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8158 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8161 MONO_REQ_GC_UNSAFE_MODE;
8163 mono_error_init (error);
8165 MonoDomain *domain = mono_domain_get ();
8166 MonoClass *field_class;
8169 g_assert (mono_object_is_transparent_proxy (this_obj));
8171 field_class = mono_class_from_mono_type (field->type);
8173 if (field_class->valuetype) {
8174 arg = mono_value_box_checked (domain, field_class, val, error);
8175 return_val_if_nok (error, FALSE);
8177 arg = *((MonoObject**)val);
8180 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8184 * mono_store_remote_field_new:
8190 * Missing documentation
8193 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8196 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8197 mono_error_cleanup (&error);
8201 * mono_store_remote_field_new_checked:
8208 * Missing documentation
8211 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8213 MONO_REQ_GC_UNSAFE_MODE;
8215 static MonoMethod *tp_store = NULL;
8217 mono_error_init (error);
8219 g_assert (mono_object_is_transparent_proxy (this_obj));
8222 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8224 mono_error_set_not_supported (error, "Linked away.");
8234 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8235 return is_ok (error);
8240 * mono_create_ftnptr:
8242 * Given a function address, create a function descriptor for it.
8243 * This is only needed on some platforms.
8246 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8248 return callbacks.create_ftnptr (domain, addr);
8252 * mono_get_addr_from_ftnptr:
8254 * Given a pointer to a function descriptor, return the function address.
8255 * This is only needed on some platforms.
8258 mono_get_addr_from_ftnptr (gpointer descr)
8260 return callbacks.get_addr_from_ftnptr (descr);
8264 * mono_string_chars:
8267 * Returns a pointer to the UCS16 characters stored in the MonoString
8270 mono_string_chars (MonoString *s)
8272 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8278 * mono_string_length:
8281 * Returns the lenght in characters of the string
8284 mono_string_length (MonoString *s)
8286 MONO_REQ_GC_UNSAFE_MODE;
8292 * mono_array_length:
8293 * @array: a MonoArray*
8295 * Returns the total number of elements in the array. This works for
8296 * both vectors and multidimensional arrays.
8299 mono_array_length (MonoArray *array)
8301 MONO_REQ_GC_UNSAFE_MODE;
8303 return array->max_length;
8307 * mono_array_addr_with_size:
8308 * @array: a MonoArray*
8309 * @size: size of the array elements
8310 * @idx: index into the array
8312 * Use this function to obtain the address for the @idx item on the
8313 * @array containing elements of size @size.
8315 * This method performs no bounds checking or type checking.
8317 * Returns the address of the @idx element in the array.
8320 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8322 MONO_REQ_GC_UNSAFE_MODE;
8324 return ((char*)(array)->vector) + size * idx;
8329 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8331 MonoDomain *domain = mono_domain_get ();
8335 mono_error_init (error);
8339 len = g_list_length (list);
8340 res = mono_array_new_checked (domain, eclass, len, error);
8341 return_val_if_nok (error, NULL);
8343 for (i = 0; list; list = list->next, i++)
8344 mono_array_set (res, gpointer, i, list->data);
8351 * The following section is purely to declare prototypes and
8352 * document the API, as these C files are processed by our
8358 * @array: array to alter
8359 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8360 * @index: index into the array
8361 * @value: value to set
8363 * Value Type version: This sets the @index's element of the @array
8364 * with elements of size sizeof(type) to the provided @value.
8366 * This macro does not attempt to perform type checking or bounds checking.
8368 * Use this to set value types in a `MonoArray`.
8370 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8375 * mono_array_setref:
8376 * @array: array to alter
8377 * @index: index into the array
8378 * @value: value to set
8380 * Reference Type version: This sets the @index's element of the
8381 * @array with elements of size sizeof(type) to the provided @value.
8383 * This macro does not attempt to perform type checking or bounds checking.
8385 * Use this to reference types in a `MonoArray`.
8387 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8393 * @array: array on which to operate on
8394 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8395 * @index: index into the array
8397 * Use this macro to retrieve the @index element of an @array and
8398 * extract the value assuming that the elements of the array match
8399 * the provided type value.
8401 * This method can be used with both arrays holding value types and
8402 * reference types. For reference types, the @type parameter should
8403 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8405 * This macro does not attempt to perform type checking or bounds checking.
8407 * Returns: The element at the @index position in the @array.
8409 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)