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 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
560 g_error ("remoting not installed");
564 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
568 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
570 g_assert_not_reached ();
574 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
575 static MonoImtTrampolineBuilder imt_trampoline_builder;
576 static gboolean always_build_imt_trampolines;
578 #if (MONO_IMT_SIZE > 32)
579 #error "MONO_IMT_SIZE cannot be larger than 32"
583 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
585 memcpy (&callbacks, cbs, sizeof (*cbs));
588 MonoRuntimeCallbacks*
589 mono_get_runtime_callbacks (void)
594 #ifndef DISABLE_REMOTING
596 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
598 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
603 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
605 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
609 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
611 imt_trampoline_builder = func;
615 mono_set_always_build_imt_trampolines (gboolean value)
617 always_build_imt_trampolines = value;
621 * mono_compile_method:
622 * @method: The method to compile.
624 * This JIT-compiles the method, and returns the pointer to the native code
628 mono_compile_method (MonoMethod *method)
631 gpointer result = mono_compile_method_checked (method, &error);
632 mono_error_cleanup (&error);
637 * mono_compile_method:
638 * @method: The method to compile.
639 * @error: set on error.
641 * This JIT-compiles the method, and returns the pointer to the native code
642 * produced. On failure returns NULL and sets @error.
645 mono_compile_method_checked (MonoMethod *method, MonoError *error)
649 MONO_REQ_GC_NEUTRAL_MODE
651 mono_error_init (error);
653 if (!callbacks.compile_method) {
654 g_error ("compile method called on uninitialized runtime");
657 res = callbacks.compile_method (method, error);
662 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
666 MONO_REQ_GC_NEUTRAL_MODE;
668 mono_error_init (error);
669 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
674 mono_runtime_create_delegate_trampoline (MonoClass *klass)
676 MONO_REQ_GC_NEUTRAL_MODE
678 return arch_create_delegate_trampoline (mono_domain_get (), klass);
681 static MonoFreeMethodFunc default_mono_free_method = NULL;
684 * mono_install_free_method:
685 * @func: pointer to the MonoFreeMethodFunc used to release a method
687 * This is an internal VM routine, it is used for the engines to
688 * register a handler to release the resources associated with a method.
690 * Methods are freed when no more references to the delegate that holds
694 mono_install_free_method (MonoFreeMethodFunc func)
696 default_mono_free_method = func;
700 * mono_runtime_free_method:
701 * @domain; domain where the method is hosted
702 * @method: method to release
704 * This routine is invoked to free the resources associated with
705 * a method that has been JIT compiled. This is used to discard
706 * methods that were used only temporarily (for example, used in marshalling)
710 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
712 MONO_REQ_GC_NEUTRAL_MODE
714 if (default_mono_free_method != NULL)
715 default_mono_free_method (domain, method);
717 mono_method_clear_object (domain, method);
719 mono_free_method (method);
723 * The vtables in the root appdomain are assumed to be reachable by other
724 * roots, and we don't use typed allocation in the other domains.
727 /* The sync block is no longer a GC pointer */
728 #define GC_HEADER_BITMAP (0)
730 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
733 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
735 MONO_REQ_GC_NEUTRAL_MODE;
737 MonoClassField *field;
743 max_size = mono_class_data_size (klass) / sizeof (gpointer);
745 max_size = klass->instance_size / sizeof (gpointer);
746 if (max_size > size) {
747 g_assert (offset <= 0);
748 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
753 /*An Ephemeron cannot be marked by sgen*/
754 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
756 memset (bitmap, 0, size / 8);
761 for (p = klass; p != NULL; p = p->parent) {
762 gpointer iter = NULL;
763 while ((field = mono_class_get_fields (p, &iter))) {
767 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
769 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
772 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
775 /* FIXME: should not happen, flag as type load error */
776 if (field->type->byref)
779 if (static_fields && field->offset == -1)
783 pos = field->offset / sizeof (gpointer);
786 type = mono_type_get_underlying_type (field->type);
787 switch (type->type) {
790 case MONO_TYPE_FNPTR:
792 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
797 if (klass->image != mono_defaults.corlib)
800 case MONO_TYPE_STRING:
801 case MONO_TYPE_SZARRAY:
802 case MONO_TYPE_CLASS:
803 case MONO_TYPE_OBJECT:
804 case MONO_TYPE_ARRAY:
805 g_assert ((field->offset % sizeof(gpointer)) == 0);
807 g_assert (pos < size || pos <= max_size);
808 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
809 *max_set = MAX (*max_set, pos);
811 case MONO_TYPE_GENERICINST:
812 if (!mono_type_generic_inst_is_valuetype (type)) {
813 g_assert ((field->offset % sizeof(gpointer)) == 0);
815 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
816 *max_set = MAX (*max_set, pos);
821 case MONO_TYPE_VALUETYPE: {
822 MonoClass *fclass = mono_class_from_mono_type (field->type);
823 if (fclass->has_references) {
824 /* remove the object header */
825 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
839 case MONO_TYPE_BOOLEAN:
843 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
854 * mono_class_compute_bitmap:
856 * Mono internal function to compute a bitmap of reference fields in a class.
859 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
861 MONO_REQ_GC_NEUTRAL_MODE;
863 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
868 * similar to the above, but sets the bits in the bitmap for any non-ref field
869 * and ignores static fields
872 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
874 MonoClassField *field;
879 max_size = class->instance_size / sizeof (gpointer);
880 if (max_size >= size) {
881 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
884 for (p = class; p != NULL; p = p->parent) {
885 gpointer iter = NULL;
886 while ((field = mono_class_get_fields (p, &iter))) {
889 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
891 /* FIXME: should not happen, flag as type load error */
892 if (field->type->byref)
895 pos = field->offset / sizeof (gpointer);
898 type = mono_type_get_underlying_type (field->type);
899 switch (type->type) {
900 #if SIZEOF_VOID_P == 8
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
914 #if SIZEOF_VOID_P == 4
918 case MONO_TYPE_FNPTR:
923 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
924 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
925 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
931 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
932 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
933 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
936 case MONO_TYPE_BOOLEAN:
939 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
941 case MONO_TYPE_STRING:
942 case MONO_TYPE_SZARRAY:
943 case MONO_TYPE_CLASS:
944 case MONO_TYPE_OBJECT:
945 case MONO_TYPE_ARRAY:
947 case MONO_TYPE_GENERICINST:
948 if (!mono_type_generic_inst_is_valuetype (type)) {
953 case MONO_TYPE_VALUETYPE: {
954 MonoClass *fclass = mono_class_from_mono_type (field->type);
955 /* remove the object header */
956 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
960 g_assert_not_reached ();
969 * mono_class_insecure_overlapping:
970 * check if a class with explicit layout has references and non-references
971 * fields overlapping.
973 * Returns: TRUE if it is insecure to load the type.
976 mono_class_insecure_overlapping (MonoClass *klass)
980 gsize default_bitmap [4] = {0};
982 gsize default_nrbitmap [4] = {0};
983 int i, insecure = FALSE;
986 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
987 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
989 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
990 int idx = i % (sizeof (bitmap [0]) * 8);
991 if (bitmap [idx] & nrbitmap [idx]) {
996 if (bitmap != default_bitmap)
998 if (nrbitmap != default_nrbitmap)
1001 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1009 ves_icall_string_alloc (int length)
1012 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1013 mono_error_set_pending_exception (&error);
1019 mono_class_compute_gc_descriptor (MonoClass *klass)
1021 MONO_REQ_GC_NEUTRAL_MODE;
1025 gsize default_bitmap [4] = {0};
1026 static gboolean gcj_inited = FALSE;
1029 mono_loader_lock ();
1031 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1032 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1035 mono_loader_unlock ();
1039 mono_class_init (klass);
1041 if (klass->gc_descr_inited)
1044 klass->gc_descr_inited = TRUE;
1045 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1047 bitmap = default_bitmap;
1048 if (klass == mono_defaults.string_class) {
1049 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1050 } else if (klass->rank) {
1051 mono_class_compute_gc_descriptor (klass->element_class);
1052 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1054 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1055 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1056 class->name_space, class->name);*/
1058 /* remove the object header */
1059 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1060 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));
1061 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1062 class->name_space, class->name);*/
1063 if (bitmap != default_bitmap)
1067 /*static int count = 0;
1070 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1071 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1073 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1074 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1076 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1077 if (bitmap != default_bitmap)
1083 * field_is_special_static:
1084 * @fklass: The MonoClass to look up.
1085 * @field: The MonoClassField describing the field.
1087 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1088 * SPECIAL_STATIC_NONE otherwise.
1091 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1093 MONO_REQ_GC_NEUTRAL_MODE;
1096 MonoCustomAttrInfo *ainfo;
1098 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1099 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1102 for (i = 0; i < ainfo->num_attrs; ++i) {
1103 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1104 if (klass->image == mono_defaults.corlib) {
1105 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1106 mono_custom_attrs_free (ainfo);
1107 return SPECIAL_STATIC_THREAD;
1109 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1110 mono_custom_attrs_free (ainfo);
1111 return SPECIAL_STATIC_CONTEXT;
1115 mono_custom_attrs_free (ainfo);
1116 return SPECIAL_STATIC_NONE;
1119 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1120 #define mix(a,b,c) { \
1121 a -= c; a ^= rot(c, 4); c += b; \
1122 b -= a; b ^= rot(a, 6); a += c; \
1123 c -= b; c ^= rot(b, 8); b += a; \
1124 a -= c; a ^= rot(c,16); c += b; \
1125 b -= a; b ^= rot(a,19); a += c; \
1126 c -= b; c ^= rot(b, 4); b += a; \
1128 #define final(a,b,c) { \
1129 c ^= b; c -= rot(b,14); \
1130 a ^= c; a -= rot(c,11); \
1131 b ^= a; b -= rot(a,25); \
1132 c ^= b; c -= rot(b,16); \
1133 a ^= c; a -= rot(c,4); \
1134 b ^= a; b -= rot(a,14); \
1135 c ^= b; c -= rot(b,24); \
1139 * mono_method_get_imt_slot:
1141 * The IMT slot is embedded into AOTed code, so this must return the same value
1142 * for the same method across all executions. This means:
1143 * - pointers shouldn't be used as hash values.
1144 * - mono_metadata_str_hash () should be used for hashing strings.
1147 mono_method_get_imt_slot (MonoMethod *method)
1149 MONO_REQ_GC_NEUTRAL_MODE;
1151 MonoMethodSignature *sig;
1153 guint32 *hashes_start, *hashes;
1157 /* This can be used to stress tests the collision code */
1161 * We do this to simplify generic sharing. It will hurt
1162 * performance in cases where a class implements two different
1163 * instantiations of the same generic interface.
1164 * The code in build_imt_slots () depends on this.
1166 if (method->is_inflated)
1167 method = ((MonoMethodInflated*)method)->declaring;
1169 sig = mono_method_signature (method);
1170 hashes_count = sig->param_count + 4;
1171 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1172 hashes = hashes_start;
1174 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1175 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1176 method->klass->name_space, method->klass->name, method->name);
1179 /* Initialize hashes */
1180 hashes [0] = mono_metadata_str_hash (method->klass->name);
1181 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1182 hashes [2] = mono_metadata_str_hash (method->name);
1183 hashes [3] = mono_metadata_type_hash (sig->ret);
1184 for (i = 0; i < sig->param_count; i++) {
1185 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1188 /* Setup internal state */
1189 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1191 /* Handle most of the hashes */
1192 while (hashes_count > 3) {
1201 /* Handle the last 3 hashes (all the case statements fall through) */
1202 switch (hashes_count) {
1203 case 3 : c += hashes [2];
1204 case 2 : b += hashes [1];
1205 case 1 : a += hashes [0];
1207 case 0: /* nothing left to add */
1211 g_free (hashes_start);
1212 /* Report the result */
1213 return c % MONO_IMT_SIZE;
1222 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1223 MONO_REQ_GC_NEUTRAL_MODE;
1225 guint32 imt_slot = mono_method_get_imt_slot (method);
1226 MonoImtBuilderEntry *entry;
1228 if (slot_num >= 0 && imt_slot != slot_num) {
1229 /* we build just a single imt slot and this is not it */
1233 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1234 entry->key = method;
1235 entry->value.vtable_slot = vtable_slot;
1236 entry->next = imt_builder [imt_slot];
1237 if (imt_builder [imt_slot] != NULL) {
1238 entry->children = imt_builder [imt_slot]->children + 1;
1239 if (entry->children == 1) {
1240 mono_stats.imt_slots_with_collisions++;
1241 *imt_collisions_bitmap |= (1 << imt_slot);
1244 entry->children = 0;
1245 mono_stats.imt_used_slots++;
1247 imt_builder [imt_slot] = entry;
1250 char *method_name = mono_method_full_name (method, TRUE);
1251 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1252 method, method_name, imt_slot, vtable_slot, entry->children);
1253 g_free (method_name);
1260 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1262 MonoMethod *method = e->key;
1263 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1267 method->klass->name_space,
1268 method->klass->name,
1271 printf (" * %s: NULL\n", message);
1277 compare_imt_builder_entries (const void *p1, const void *p2) {
1278 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1279 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1281 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1285 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1287 MONO_REQ_GC_NEUTRAL_MODE;
1289 int count = end - start;
1290 int chunk_start = out_array->len;
1293 for (i = start; i < end; ++i) {
1294 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1295 item->key = sorted_array [i]->key;
1296 item->value = sorted_array [i]->value;
1297 item->has_target_code = sorted_array [i]->has_target_code;
1298 item->is_equals = TRUE;
1300 item->check_target_idx = out_array->len + 1;
1302 item->check_target_idx = 0;
1303 g_ptr_array_add (out_array, item);
1306 int middle = start + count / 2;
1307 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1309 item->key = sorted_array [middle]->key;
1310 item->is_equals = FALSE;
1311 g_ptr_array_add (out_array, item);
1312 imt_emit_ir (sorted_array, start, middle, out_array);
1313 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1319 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1320 MONO_REQ_GC_NEUTRAL_MODE;
1322 int number_of_entries = entries->children + 1;
1323 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1324 GPtrArray *result = g_ptr_array_new ();
1325 MonoImtBuilderEntry *current_entry;
1328 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1329 sorted_array [i] = current_entry;
1331 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1333 /*for (i = 0; i < number_of_entries; i++) {
1334 print_imt_entry (" sorted array:", sorted_array [i], i);
1337 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1339 g_free (sorted_array);
1344 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1346 MONO_REQ_GC_NEUTRAL_MODE;
1348 if (imt_builder_entry != NULL) {
1349 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1350 /* No collision, return the vtable slot contents */
1351 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1353 /* Collision, build the trampoline */
1354 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1357 result = imt_trampoline_builder (vtable, domain,
1358 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1359 for (i = 0; i < imt_ir->len; ++i)
1360 g_free (g_ptr_array_index (imt_ir, i));
1361 g_ptr_array_free (imt_ir, TRUE);
1373 static MonoImtBuilderEntry*
1374 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1377 * LOCKING: requires the loader and domain locks.
1381 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1383 MONO_REQ_GC_NEUTRAL_MODE;
1387 guint32 imt_collisions_bitmap = 0;
1388 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1389 int method_count = 0;
1390 gboolean record_method_count_for_max_collisions = FALSE;
1391 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1394 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1396 for (i = 0; i < klass->interface_offsets_count; ++i) {
1397 MonoClass *iface = klass->interfaces_packed [i];
1398 int interface_offset = klass->interface_offsets_packed [i];
1399 int method_slot_in_interface, vt_slot;
1401 if (mono_class_has_variant_generic_params (iface))
1402 has_variant_iface = TRUE;
1404 mono_class_setup_methods (iface);
1405 vt_slot = interface_offset;
1406 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1409 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1411 * The imt slot of the method is the same as for its declaring method,
1412 * see the comment in mono_method_get_imt_slot (), so we can
1413 * avoid inflating methods which will be discarded by
1414 * add_imt_builder_entry anyway.
1416 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1417 if (mono_method_get_imt_slot (method) != slot_num) {
1422 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1423 if (method->is_generic) {
1424 has_generic_virtual = TRUE;
1429 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1430 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1435 if (extra_interfaces) {
1436 int interface_offset = klass->vtable_size;
1438 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1439 MonoClass* iface = (MonoClass *)list_item->data;
1440 int method_slot_in_interface;
1441 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1442 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1444 if (method->is_generic)
1445 has_generic_virtual = TRUE;
1446 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1448 interface_offset += iface->method.count;
1451 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1452 /* overwrite the imt slot only if we're building all the entries or if
1453 * we're building this specific one
1455 if (slot_num < 0 || i == slot_num) {
1456 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1459 if (imt_builder [i]) {
1460 MonoImtBuilderEntry *entry;
1462 /* Link entries with imt_builder [i] */
1463 for (entry = entries; entry->next; entry = entry->next) {
1465 MonoMethod *method = (MonoMethod*)entry->key;
1466 char *method_name = mono_method_full_name (method, TRUE);
1467 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1468 g_free (method_name);
1471 entry->next = imt_builder [i];
1472 entries->children += imt_builder [i]->children + 1;
1474 imt_builder [i] = entries;
1477 if (has_generic_virtual || has_variant_iface) {
1479 * There might be collisions later when the the trampoline is expanded.
1481 imt_collisions_bitmap |= (1 << i);
1484 * The IMT trampoline might be called with an instance of one of the
1485 * generic virtual methods, so has to fallback to the IMT trampoline.
1487 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1489 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1492 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1496 if (imt_builder [i] != NULL) {
1497 int methods_in_slot = imt_builder [i]->children + 1;
1498 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1499 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1500 record_method_count_for_max_collisions = TRUE;
1502 method_count += methods_in_slot;
1506 mono_stats.imt_number_of_methods += method_count;
1507 if (record_method_count_for_max_collisions) {
1508 mono_stats.imt_method_count_when_max_collisions = method_count;
1511 for (i = 0; i < MONO_IMT_SIZE; i++) {
1512 MonoImtBuilderEntry* entry = imt_builder [i];
1513 while (entry != NULL) {
1514 MonoImtBuilderEntry* next = entry->next;
1519 g_free (imt_builder);
1520 /* we OR the bitmap since we may build just a single imt slot at a time */
1521 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1525 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1526 MONO_REQ_GC_NEUTRAL_MODE;
1528 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1532 * mono_vtable_build_imt_slot:
1533 * @vtable: virtual object table struct
1534 * @imt_slot: slot in the IMT table
1536 * Fill the given @imt_slot in the IMT table of @vtable with
1537 * a trampoline or a trampoline for the case of collisions.
1538 * This is part of the internal mono API.
1540 * LOCKING: Take the domain lock.
1543 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1545 MONO_REQ_GC_NEUTRAL_MODE;
1547 gpointer *imt = (gpointer*)vtable;
1548 imt -= MONO_IMT_SIZE;
1549 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1551 /* no support for extra interfaces: the proxy objects will need
1552 * to build the complete IMT
1553 * Update and heck needs to ahppen inside the proper domain lock, as all
1554 * the changes made to a MonoVTable.
1556 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1557 mono_domain_lock (vtable->domain);
1558 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1559 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1560 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1561 mono_domain_unlock (vtable->domain);
1562 mono_loader_unlock ();
1565 #define THUNK_THRESHOLD 10
1568 * mono_method_alloc_generic_virtual_trampoline:
1570 * @size: size in bytes
1572 * Allocs size bytes to be used for the code of a generic virtual
1573 * trampoline. It's either allocated from the domain's code manager or
1574 * reused from a previously invalidated piece.
1576 * LOCKING: The domain lock must be held.
1579 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1581 MONO_REQ_GC_NEUTRAL_MODE;
1583 static gboolean inited = FALSE;
1584 static int generic_virtual_trampolines_size = 0;
1587 mono_counters_register ("Generic virtual trampoline bytes",
1588 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1591 generic_virtual_trampolines_size += size;
1593 return mono_domain_code_reserve (domain, size);
1596 typedef struct _GenericVirtualCase {
1600 struct _GenericVirtualCase *next;
1601 } GenericVirtualCase;
1604 * get_generic_virtual_entries:
1606 * Return IMT entries for the generic virtual method instances and
1607 * variant interface methods for vtable slot
1610 static MonoImtBuilderEntry*
1611 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1613 MONO_REQ_GC_NEUTRAL_MODE;
1615 GenericVirtualCase *list;
1616 MonoImtBuilderEntry *entries;
1618 mono_domain_lock (domain);
1619 if (!domain->generic_virtual_cases)
1620 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1622 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1625 for (; list; list = list->next) {
1626 MonoImtBuilderEntry *entry;
1628 if (list->count < THUNK_THRESHOLD)
1631 entry = g_new0 (MonoImtBuilderEntry, 1);
1632 entry->key = list->method;
1633 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1634 entry->has_target_code = 1;
1636 entry->children = entries->children + 1;
1637 entry->next = entries;
1641 mono_domain_unlock (domain);
1643 /* FIXME: Leaking memory ? */
1648 * mono_method_add_generic_virtual_invocation:
1650 * @vtable_slot: pointer to the vtable slot
1651 * @method: the inflated generic virtual method
1652 * @code: the method's code
1654 * Registers a call via unmanaged code to a generic virtual method
1655 * instantiation or variant interface method. If the number of calls reaches a threshold
1656 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1657 * virtual method trampoline.
1660 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1661 gpointer *vtable_slot,
1662 MonoMethod *method, gpointer code)
1664 MONO_REQ_GC_NEUTRAL_MODE;
1666 static gboolean inited = FALSE;
1667 static int num_added = 0;
1668 static int num_freed = 0;
1670 GenericVirtualCase *gvc, *list;
1671 MonoImtBuilderEntry *entries;
1675 mono_domain_lock (domain);
1676 if (!domain->generic_virtual_cases)
1677 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1680 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1681 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1685 /* Check whether the case was already added */
1686 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1689 if (gvc->method == method)
1694 /* If not found, make a new one */
1696 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1697 gvc->method = method;
1700 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1702 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1707 if (++gvc->count == THUNK_THRESHOLD) {
1708 gpointer *old_thunk = (void **)*vtable_slot;
1709 gpointer vtable_trampoline = NULL;
1710 gpointer imt_trampoline = NULL;
1712 if ((gpointer)vtable_slot < (gpointer)vtable) {
1713 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1714 int imt_slot = MONO_IMT_SIZE + displacement;
1716 /* Force the rebuild of the trampoline at the next call */
1717 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1718 *vtable_slot = imt_trampoline;
1720 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1722 entries = get_generic_virtual_entries (domain, vtable_slot);
1724 sorted = imt_sort_slot_entries (entries);
1726 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1730 MonoImtBuilderEntry *next = entries->next;
1735 for (i = 0; i < sorted->len; ++i)
1736 g_free (g_ptr_array_index (sorted, i));
1737 g_ptr_array_free (sorted, TRUE);
1739 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1744 mono_domain_unlock (domain);
1747 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1750 * mono_class_vtable:
1751 * @domain: the application domain
1752 * @class: the class to initialize
1754 * VTables are domain specific because we create domain specific code, and
1755 * they contain the domain specific static class data.
1756 * On failure, NULL is returned, and class->exception_type is set.
1759 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1762 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1763 mono_error_cleanup (&error);
1768 * mono_class_vtable_full:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1771 * @error set on failure.
1773 * VTables are domain specific because we create domain specific code, and
1774 * they contain the domain specific static class data.
1777 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1779 MONO_REQ_GC_UNSAFE_MODE;
1781 MonoClassRuntimeInfo *runtime_info;
1783 mono_error_init (error);
1787 if (mono_class_has_failure (klass)) {
1788 mono_error_set_for_class_failure (error, klass);
1792 /* this check can be inlined in jitted code, too */
1793 runtime_info = klass->runtime_info;
1794 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1795 return runtime_info->domain_vtables [domain->domain_id];
1796 return mono_class_create_runtime_vtable (domain, klass, error);
1800 * mono_class_try_get_vtable:
1801 * @domain: the application domain
1802 * @class: the class to initialize
1804 * This function tries to get the associated vtable from @class if
1805 * it was already created.
1808 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1810 MONO_REQ_GC_NEUTRAL_MODE;
1812 MonoClassRuntimeInfo *runtime_info;
1816 runtime_info = klass->runtime_info;
1817 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1818 return runtime_info->domain_vtables [domain->domain_id];
1823 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1825 MONO_REQ_GC_NEUTRAL_MODE;
1827 size_t alloc_offset;
1830 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1831 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1832 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1834 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1835 g_assert ((imt_table_bytes & 7) == 4);
1842 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1846 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1848 MONO_REQ_GC_UNSAFE_MODE;
1851 MonoClassRuntimeInfo *runtime_info, *old_info;
1852 MonoClassField *field;
1854 int i, vtable_slots;
1855 size_t imt_table_bytes;
1857 guint32 vtable_size, class_size;
1859 gpointer *interface_offsets;
1861 mono_error_init (error);
1863 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1864 mono_domain_lock (domain);
1865 runtime_info = klass->runtime_info;
1866 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1867 mono_domain_unlock (domain);
1868 mono_loader_unlock ();
1869 return runtime_info->domain_vtables [domain->domain_id];
1871 if (!klass->inited || mono_class_has_failure (klass)) {
1872 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1873 mono_domain_unlock (domain);
1874 mono_loader_unlock ();
1875 mono_error_set_for_class_failure (error, klass);
1880 /* Array types require that their element type be valid*/
1881 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1882 MonoClass *element_class = klass->element_class;
1883 if (!element_class->inited)
1884 mono_class_init (element_class);
1886 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1887 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1888 mono_class_setup_vtable (element_class);
1890 if (mono_class_has_failure (element_class)) {
1891 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1892 if (!mono_class_has_failure (klass))
1893 mono_class_set_type_load_failure (klass, "");
1894 mono_domain_unlock (domain);
1895 mono_loader_unlock ();
1896 mono_error_set_for_class_failure (error, klass);
1902 * For some classes, mono_class_init () already computed klass->vtable_size, and
1903 * that is all that is needed because of the vtable trampolines.
1905 if (!klass->vtable_size)
1906 mono_class_setup_vtable (klass);
1908 if (mono_class_is_ginst (klass) && !klass->vtable)
1909 mono_class_check_vtable_constraints (klass, NULL);
1911 /* Initialize klass->has_finalize */
1912 mono_class_has_finalizer (klass);
1914 if (mono_class_has_failure (klass)) {
1915 mono_domain_unlock (domain);
1916 mono_loader_unlock ();
1917 mono_error_set_for_class_failure (error, klass);
1921 vtable_slots = klass->vtable_size;
1922 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1923 class_size = mono_class_data_size (klass);
1927 if (klass->interface_offsets_count) {
1928 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1929 mono_stats.imt_number_of_tables++;
1930 mono_stats.imt_tables_size += imt_table_bytes;
1932 imt_table_bytes = 0;
1935 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1937 mono_stats.used_class_count++;
1938 mono_stats.class_vtable_size += vtable_size;
1940 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1941 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1942 g_assert (!((gsize)vt & 7));
1945 vt->rank = klass->rank;
1946 vt->domain = domain;
1948 mono_class_compute_gc_descriptor (klass);
1950 * We can't use typed allocation in the non-root domains, since the
1951 * collector needs the GC descriptor stored in the vtable even after
1952 * the mempool containing the vtable is destroyed when the domain is
1953 * unloaded. An alternative might be to allocate vtables in the GC
1954 * heap, but this does not seem to work (it leads to crashes inside
1955 * libgc). If that approach is tried, two gc descriptors need to be
1956 * allocated for each class: one for the root domain, and one for all
1957 * other domains. The second descriptor should contain a bit for the
1958 * vtable field in MonoObject, since we can no longer assume the
1959 * vtable is reachable by other roots after the appdomain is unloaded.
1961 #ifdef HAVE_BOEHM_GC
1962 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1963 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1966 vt->gc_descr = klass->gc_descr;
1968 gc_bits = mono_gc_get_vtable_bits (klass);
1969 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1971 vt->gc_bits = gc_bits;
1974 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1975 if (klass->has_static_refs) {
1976 MonoGCDescriptor statics_gc_descr;
1978 gsize default_bitmap [4] = {0};
1981 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1982 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1983 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1984 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1985 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1986 if (bitmap != default_bitmap)
1989 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1991 vt->has_static_fields = TRUE;
1992 mono_stats.class_static_data_size += class_size;
1996 while ((field = mono_class_get_fields (klass, &iter))) {
1997 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1999 if (mono_field_is_deleted (field))
2001 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2002 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2003 if (special_static != SPECIAL_STATIC_NONE) {
2004 guint32 size, offset;
2006 gsize default_bitmap [4] = {0};
2011 if (mono_type_is_reference (field->type)) {
2012 default_bitmap [0] = 1;
2014 bitmap = default_bitmap;
2015 } else if (mono_type_is_struct (field->type)) {
2016 fclass = mono_class_from_mono_type (field->type);
2017 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2018 numbits = max_set + 1;
2020 default_bitmap [0] = 0;
2022 bitmap = default_bitmap;
2024 size = mono_type_size (field->type, &align);
2025 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2026 if (!domain->special_static_fields)
2027 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2028 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2029 if (bitmap != default_bitmap)
2032 * This marks the field as special static to speed up the
2033 * checks in mono_field_static_get/set_value ().
2039 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2040 MonoClass *fklass = mono_class_from_mono_type (field->type);
2041 const char *data = mono_field_get_data (field);
2043 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2044 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2045 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2048 if (fklass->valuetype) {
2049 memcpy (t, data, mono_class_value_size (fklass, NULL));
2051 /* it's a pointer type: add check */
2052 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2059 vt->max_interface_id = klass->max_interface_id;
2060 vt->interface_bitmap = klass->interface_bitmap;
2062 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2063 // class->name, klass->interface_offsets_count);
2065 /* Initialize vtable */
2066 if (callbacks.get_vtable_trampoline) {
2067 // This also covers the AOT case
2068 for (i = 0; i < klass->vtable_size; ++i) {
2069 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2072 mono_class_setup_vtable (klass);
2074 for (i = 0; i < klass->vtable_size; ++i) {
2077 cm = klass->vtable [i];
2079 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2080 if (!is_ok (error)) {
2081 mono_domain_unlock (domain);
2082 mono_loader_unlock ();
2089 if (imt_table_bytes) {
2090 /* Now that the vtable is full, we can actually fill up the IMT */
2091 for (i = 0; i < MONO_IMT_SIZE; ++i)
2092 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2096 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2097 * re-acquire them and check if another thread has created the vtable in the meantime.
2099 /* Special case System.MonoType to avoid infinite recursion */
2100 if (klass != mono_defaults.runtimetype_class) {
2101 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2102 if (!is_ok (error)) {
2103 mono_domain_unlock (domain);
2104 mono_loader_unlock ();
2108 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2109 /* This is unregistered in
2110 unregister_vtable_reflection_type() in
2112 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2115 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2117 /* class_vtable_array keeps an array of created vtables
2119 g_ptr_array_add (domain->class_vtable_array, vt);
2120 /* klass->runtime_info is protected by the loader lock, both when
2121 * it it enlarged and when it is stored info.
2125 * Store the vtable in klass->runtime_info.
2126 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2128 mono_memory_barrier ();
2130 old_info = klass->runtime_info;
2131 if (old_info && old_info->max_domain >= domain->domain_id) {
2132 /* someone already created a large enough runtime info */
2133 old_info->domain_vtables [domain->domain_id] = vt;
2135 int new_size = domain->domain_id;
2137 new_size = MAX (new_size, old_info->max_domain);
2139 /* make the new size a power of two */
2141 while (new_size > i)
2144 /* this is a bounded memory retention issue: may want to
2145 * handle it differently when we'll have a rcu-like system.
2147 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2148 runtime_info->max_domain = new_size - 1;
2149 /* copy the stuff from the older info */
2151 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2153 runtime_info->domain_vtables [domain->domain_id] = vt;
2155 mono_memory_barrier ();
2156 klass->runtime_info = runtime_info;
2159 if (klass == mono_defaults.runtimetype_class) {
2160 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2161 if (!is_ok (error)) {
2162 mono_domain_unlock (domain);
2163 mono_loader_unlock ();
2167 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2168 /* This is unregistered in
2169 unregister_vtable_reflection_type() in
2171 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2174 mono_domain_unlock (domain);
2175 mono_loader_unlock ();
2177 /* make sure the parent is initialized */
2178 /*FIXME shouldn't this fail the current type?*/
2180 mono_class_vtable_full (domain, klass->parent, error);
2185 #ifndef DISABLE_REMOTING
2187 * mono_class_proxy_vtable:
2188 * @domain: the application domain
2189 * @remove_class: the remote class
2190 * @error: set on error
2192 * Creates a vtable for transparent proxies. It is basically
2193 * a copy of the real vtable of the class wrapped in @remote_class,
2194 * but all function pointers invoke the remoting functions, and
2195 * vtable->klass points to the transparent proxy class, and not to @class.
2197 * On failure returns NULL and sets @error
2200 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2202 MONO_REQ_GC_UNSAFE_MODE;
2204 MonoVTable *vt, *pvt;
2205 int i, j, vtsize, extra_interface_vtsize = 0;
2206 guint32 max_interface_id;
2208 GSList *extra_interfaces = NULL;
2209 MonoClass *klass = remote_class->proxy_class;
2210 gpointer *interface_offsets;
2211 uint8_t *bitmap = NULL;
2213 size_t imt_table_bytes;
2215 #ifdef COMPRESSED_INTERFACE_BITMAP
2219 mono_error_init (error);
2221 vt = mono_class_vtable (domain, klass);
2222 g_assert (vt); /*FIXME property handle failure*/
2223 max_interface_id = vt->max_interface_id;
2225 /* Calculate vtable space for extra interfaces */
2226 for (j = 0; j < remote_class->interface_count; j++) {
2227 MonoClass* iclass = remote_class->interfaces[j];
2231 /*FIXME test for interfaces with variant generic arguments*/
2232 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2233 continue; /* interface implemented by the class */
2234 if (g_slist_find (extra_interfaces, iclass))
2237 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2239 method_count = mono_class_num_methods (iclass);
2241 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2245 for (i = 0; i < ifaces->len; ++i) {
2246 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2247 /*FIXME test for interfaces with variant generic arguments*/
2248 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2249 continue; /* interface implemented by the class */
2250 if (g_slist_find (extra_interfaces, ic))
2252 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2253 method_count += mono_class_num_methods (ic);
2255 g_ptr_array_free (ifaces, TRUE);
2259 extra_interface_vtsize += method_count * sizeof (gpointer);
2260 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2263 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2264 mono_stats.imt_number_of_tables++;
2265 mono_stats.imt_tables_size += imt_table_bytes;
2267 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2269 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2271 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2272 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2273 g_assert (!((gsize)pvt & 7));
2275 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2277 pvt->klass = mono_defaults.transparent_proxy_class;
2278 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2279 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2281 /* initialize vtable */
2282 mono_class_setup_vtable (klass);
2283 for (i = 0; i < klass->vtable_size; ++i) {
2286 if ((cm = klass->vtable [i])) {
2287 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2291 pvt->vtable [i] = NULL;
2294 if (mono_class_is_abstract (klass)) {
2295 /* create trampolines for abstract methods */
2296 for (k = klass; k; k = k->parent) {
2298 gpointer iter = NULL;
2299 while ((m = mono_class_get_methods (k, &iter)))
2300 if (!pvt->vtable [m->slot]) {
2301 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2308 pvt->max_interface_id = max_interface_id;
2309 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2310 #ifdef COMPRESSED_INTERFACE_BITMAP
2311 bitmap = (uint8_t *)g_malloc0 (bsize);
2313 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2316 for (i = 0; i < klass->interface_offsets_count; ++i) {
2317 int interface_id = klass->interfaces_packed [i]->interface_id;
2318 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2321 if (extra_interfaces) {
2322 int slot = klass->vtable_size;
2328 /* Create trampolines for the methods of the interfaces */
2329 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2330 interf = (MonoClass *)list_item->data;
2332 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2336 while ((cm = mono_class_get_methods (interf, &iter))) {
2337 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2342 slot += mono_class_num_methods (interf);
2346 /* Now that the vtable is full, we can actually fill up the IMT */
2347 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2348 if (extra_interfaces) {
2349 g_slist_free (extra_interfaces);
2352 #ifdef COMPRESSED_INTERFACE_BITMAP
2353 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2354 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2355 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2358 pvt->interface_bitmap = bitmap;
2362 if (extra_interfaces)
2363 g_slist_free (extra_interfaces);
2364 #ifdef COMPRESSED_INTERFACE_BITMAP
2370 #endif /* DISABLE_REMOTING */
2373 * mono_class_field_is_special_static:
2375 * Returns whether @field is a thread/context static field.
2378 mono_class_field_is_special_static (MonoClassField *field)
2380 MONO_REQ_GC_NEUTRAL_MODE
2382 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2384 if (mono_field_is_deleted (field))
2386 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2387 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2394 * mono_class_field_get_special_static_type:
2395 * @field: The MonoClassField describing the field.
2397 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2398 * SPECIAL_STATIC_NONE otherwise.
2401 mono_class_field_get_special_static_type (MonoClassField *field)
2403 MONO_REQ_GC_NEUTRAL_MODE
2405 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2406 return SPECIAL_STATIC_NONE;
2407 if (mono_field_is_deleted (field))
2408 return SPECIAL_STATIC_NONE;
2409 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2410 return field_is_special_static (field->parent, field);
2411 return SPECIAL_STATIC_NONE;
2415 * mono_class_has_special_static_fields:
2417 * Returns whenever @klass has any thread/context static fields.
2420 mono_class_has_special_static_fields (MonoClass *klass)
2422 MONO_REQ_GC_NEUTRAL_MODE
2424 MonoClassField *field;
2428 while ((field = mono_class_get_fields (klass, &iter))) {
2429 g_assert (field->parent == klass);
2430 if (mono_class_field_is_special_static (field))
2437 #ifndef DISABLE_REMOTING
2439 * create_remote_class_key:
2440 * Creates an array of pointers that can be used as a hash key for a remote class.
2441 * The first element of the array is the number of pointers.
2444 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2446 MONO_REQ_GC_NEUTRAL_MODE;
2451 if (remote_class == NULL) {
2452 if (mono_class_is_interface (extra_class)) {
2453 key = (void **)g_malloc (sizeof(gpointer) * 3);
2454 key [0] = GINT_TO_POINTER (2);
2455 key [1] = mono_defaults.marshalbyrefobject_class;
2456 key [2] = extra_class;
2458 key = (void **)g_malloc (sizeof(gpointer) * 2);
2459 key [0] = GINT_TO_POINTER (1);
2460 key [1] = extra_class;
2463 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2464 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2465 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2466 key [1] = remote_class->proxy_class;
2468 // Keep the list of interfaces sorted
2469 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2470 if (extra_class && remote_class->interfaces [i] > extra_class) {
2471 key [j++] = extra_class;
2474 key [j] = remote_class->interfaces [i];
2477 key [j] = extra_class;
2479 // Replace the old class. The interface list is the same
2480 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2481 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2482 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2483 for (i = 0; i < remote_class->interface_count; i++)
2484 key [2 + i] = remote_class->interfaces [i];
2492 * copy_remote_class_key:
2494 * Make a copy of KEY in the domain and return the copy.
2497 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2499 MONO_REQ_GC_NEUTRAL_MODE
2501 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2502 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2504 memcpy (mp_key, key, key_size);
2510 * mono_remote_class:
2511 * @domain: the application domain
2512 * @class_name: name of the remote class
2513 * @error: set on error
2515 * Creates and initializes a MonoRemoteClass object for a remote type.
2517 * On failure returns NULL and sets @error
2520 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2522 MONO_REQ_GC_UNSAFE_MODE;
2524 MonoRemoteClass *rc;
2525 gpointer* key, *mp_key;
2528 mono_error_init (error);
2530 key = create_remote_class_key (NULL, proxy_class);
2532 mono_domain_lock (domain);
2533 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2537 mono_domain_unlock (domain);
2541 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2542 if (!is_ok (error)) {
2544 mono_domain_unlock (domain);
2548 mp_key = copy_remote_class_key (domain, key);
2552 if (mono_class_is_interface (proxy_class)) {
2553 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2554 rc->interface_count = 1;
2555 rc->interfaces [0] = proxy_class;
2556 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2558 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2559 rc->interface_count = 0;
2560 rc->proxy_class = proxy_class;
2563 rc->default_vtable = NULL;
2564 rc->xdomain_vtable = NULL;
2565 rc->proxy_class_name = name;
2566 #ifndef DISABLE_PERFCOUNTERS
2567 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2570 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2572 mono_domain_unlock (domain);
2577 * clone_remote_class:
2578 * Creates a copy of the remote_class, adding the provided class or interface
2580 static MonoRemoteClass*
2581 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2583 MONO_REQ_GC_NEUTRAL_MODE;
2585 MonoRemoteClass *rc;
2586 gpointer* key, *mp_key;
2588 key = create_remote_class_key (remote_class, extra_class);
2589 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2595 mp_key = copy_remote_class_key (domain, key);
2599 if (mono_class_is_interface (extra_class)) {
2601 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2602 rc->proxy_class = remote_class->proxy_class;
2603 rc->interface_count = remote_class->interface_count + 1;
2605 // Keep the list of interfaces sorted, since the hash key of
2606 // the remote class depends on this
2607 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2608 if (remote_class->interfaces [i] > extra_class && i == j)
2609 rc->interfaces [j++] = extra_class;
2610 rc->interfaces [j] = remote_class->interfaces [i];
2613 rc->interfaces [j] = extra_class;
2615 // Replace the old class. The interface array is the same
2616 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2617 rc->proxy_class = extra_class;
2618 rc->interface_count = remote_class->interface_count;
2619 if (rc->interface_count > 0)
2620 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2623 rc->default_vtable = NULL;
2624 rc->xdomain_vtable = NULL;
2625 rc->proxy_class_name = remote_class->proxy_class_name;
2627 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2633 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2635 MONO_REQ_GC_UNSAFE_MODE;
2637 mono_error_init (error);
2639 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2640 mono_domain_lock (domain);
2641 if (rp->target_domain_id != -1) {
2642 if (remote_class->xdomain_vtable == NULL)
2643 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2644 mono_domain_unlock (domain);
2645 mono_loader_unlock ();
2646 return_val_if_nok (error, NULL);
2647 return remote_class->xdomain_vtable;
2649 if (remote_class->default_vtable == NULL) {
2652 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2653 klass = mono_class_from_mono_type (type);
2655 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)))
2656 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2659 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2660 /* N.B. both branches of the if modify error */
2661 if (!is_ok (error)) {
2662 mono_domain_unlock (domain);
2663 mono_loader_unlock ();
2668 mono_domain_unlock (domain);
2669 mono_loader_unlock ();
2670 return remote_class->default_vtable;
2674 * mono_upgrade_remote_class:
2675 * @domain: the application domain
2676 * @tproxy: the proxy whose remote class has to be upgraded.
2677 * @klass: class to which the remote class can be casted.
2678 * @error: set on error
2680 * Updates the vtable of the remote class by adding the necessary method slots
2681 * and interface offsets so it can be safely casted to klass. klass can be a
2682 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2685 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2687 MONO_REQ_GC_UNSAFE_MODE;
2689 MonoTransparentProxy *tproxy;
2690 MonoRemoteClass *remote_class;
2691 gboolean redo_vtable;
2693 mono_error_init (error);
2694 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2695 mono_domain_lock (domain);
2697 tproxy = (MonoTransparentProxy*) proxy_object;
2698 remote_class = tproxy->remote_class;
2700 if (mono_class_is_interface (klass)) {
2703 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2704 if (remote_class->interfaces [i] == klass)
2705 redo_vtable = FALSE;
2708 redo_vtable = (remote_class->proxy_class != klass);
2712 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2713 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2719 mono_domain_unlock (domain);
2720 mono_loader_unlock ();
2721 return is_ok (error);
2723 #endif /* DISABLE_REMOTING */
2727 * mono_object_get_virtual_method:
2728 * @obj: object to operate on.
2731 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2732 * the instance of a callvirt of method.
2735 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2737 MONO_REQ_GC_UNSAFE_MODE;
2740 MonoMethod **vtable;
2741 gboolean is_proxy = FALSE;
2742 MonoMethod *res = NULL;
2744 klass = mono_object_class (obj);
2745 #ifndef DISABLE_REMOTING
2746 if (klass == mono_defaults.transparent_proxy_class) {
2747 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2752 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2755 mono_class_setup_vtable (klass);
2756 vtable = klass->vtable;
2758 if (method->slot == -1) {
2759 /* method->slot might not be set for instances of generic methods */
2760 if (method->is_inflated) {
2761 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2762 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2765 g_assert_not_reached ();
2769 /* check method->slot is a valid index: perform isinstance? */
2770 if (method->slot != -1) {
2771 if (mono_class_is_interface (method->klass)) {
2773 gboolean variance_used = FALSE;
2774 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2775 g_assert (iface_offset > 0);
2776 res = vtable [iface_offset + method->slot];
2779 res = vtable [method->slot];
2783 #ifndef DISABLE_REMOTING
2785 /* It may be an interface, abstract class method or generic method */
2786 if (!res || mono_method_signature (res)->generic_param_count)
2789 /* generic methods demand invoke_with_check */
2790 if (mono_method_signature (res)->generic_param_count)
2791 res = mono_marshal_get_remoting_invoke_with_check (res);
2794 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2795 res = mono_cominterop_get_invoke (res);
2798 res = mono_marshal_get_remoting_invoke (res);
2803 if (method->is_inflated) {
2805 /* Have to inflate the result */
2806 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2807 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2817 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2819 MONO_REQ_GC_UNSAFE_MODE;
2821 MonoObject *result = NULL;
2823 g_assert (callbacks.runtime_invoke);
2825 mono_error_init (error);
2827 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2828 mono_profiler_method_start_invoke (method);
2830 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2832 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2833 mono_profiler_method_end_invoke (method);
2835 if (!mono_error_ok (error))
2842 * mono_runtime_invoke:
2843 * @method: method to invoke
2844 * @obJ: object instance
2845 * @params: arguments to the method
2846 * @exc: exception information.
2848 * Invokes the method represented by @method on the object @obj.
2850 * obj is the 'this' pointer, it should be NULL for static
2851 * methods, a MonoObject* for object instances and a pointer to
2852 * the value type for value types.
2854 * The params array contains the arguments to the method with the
2855 * same convention: MonoObject* pointers for object instances and
2856 * pointers to the value type otherwise.
2858 * From unmanaged code you'll usually use the
2859 * mono_runtime_invoke() variant.
2861 * Note that this function doesn't handle virtual methods for
2862 * you, it will exec the exact method you pass: we still need to
2863 * expose a function to lookup the derived class implementation
2864 * of a virtual method (there are examples of this in the code,
2867 * You can pass NULL as the exc argument if you don't want to
2868 * catch exceptions, otherwise, *exc will be set to the exception
2869 * thrown, if any. if an exception is thrown, you can't use the
2870 * MonoObject* result from the function.
2872 * If the method returns a value type, it is boxed in an object
2876 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2881 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2882 if (*exc == NULL && !mono_error_ok(&error)) {
2883 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2885 mono_error_cleanup (&error);
2887 res = mono_runtime_invoke_checked (method, obj, params, &error);
2888 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2894 * mono_runtime_try_invoke:
2895 * @method: method to invoke
2896 * @obJ: object instance
2897 * @params: arguments to the method
2898 * @exc: exception information.
2899 * @error: set on error
2901 * Invokes the method represented by @method on the object @obj.
2903 * obj is the 'this' pointer, it should be NULL for static
2904 * methods, a MonoObject* for object instances and a pointer to
2905 * the value type for value types.
2907 * The params array contains the arguments to the method with the
2908 * same convention: MonoObject* pointers for object instances and
2909 * pointers to the value type otherwise.
2911 * From unmanaged code you'll usually use the
2912 * mono_runtime_invoke() variant.
2914 * Note that this function doesn't handle virtual methods for
2915 * you, it will exec the exact method you pass: we still need to
2916 * expose a function to lookup the derived class implementation
2917 * of a virtual method (there are examples of this in the code,
2920 * For this function, you must not pass NULL as the exc argument if
2921 * you don't want to catch exceptions, use
2922 * mono_runtime_invoke_checked(). If an exception is thrown, you
2923 * can't use the MonoObject* result from the function.
2925 * If this method cannot be invoked, @error will be set and @exc and
2926 * the return value must not be used.
2928 * If the method returns a value type, it is boxed in an object
2932 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2934 MONO_REQ_GC_UNSAFE_MODE;
2936 g_assert (exc != NULL);
2938 if (mono_runtime_get_no_exec ())
2939 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2941 return do_runtime_invoke (method, obj, params, exc, error);
2945 * mono_runtime_invoke_checked:
2946 * @method: method to invoke
2947 * @obJ: object instance
2948 * @params: arguments to the method
2949 * @error: set on error
2951 * Invokes the method represented by @method on the object @obj.
2953 * obj is the 'this' pointer, it should be NULL for static
2954 * methods, a MonoObject* for object instances and a pointer to
2955 * the value type for value types.
2957 * The params array contains the arguments to the method with the
2958 * same convention: MonoObject* pointers for object instances and
2959 * pointers to the value type otherwise.
2961 * From unmanaged code you'll usually use the
2962 * mono_runtime_invoke() variant.
2964 * Note that this function doesn't handle virtual methods for
2965 * you, it will exec the exact method you pass: we still need to
2966 * expose a function to lookup the derived class implementation
2967 * of a virtual method (there are examples of this in the code,
2970 * If an exception is thrown, you can't use the MonoObject* result
2971 * from the function.
2973 * If this method cannot be invoked, @error will be set. If the
2974 * method throws an exception (and we're in coop mode) the exception
2975 * will be set in @error.
2977 * If the method returns a value type, it is boxed in an object
2981 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2983 MONO_REQ_GC_UNSAFE_MODE;
2985 if (mono_runtime_get_no_exec ())
2986 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2988 return do_runtime_invoke (method, obj, params, NULL, error);
2992 * mono_method_get_unmanaged_thunk:
2993 * @method: method to generate a thunk for.
2995 * Returns an unmanaged->managed thunk that can be used to call
2996 * a managed method directly from C.
2998 * The thunk's C signature closely matches the managed signature:
3000 * C#: public bool Equals (object obj);
3001 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3002 * MonoObject*, MonoException**);
3004 * The 1st ("this") parameter must not be used with static methods:
3006 * C#: public static bool ReferenceEquals (object a, object b);
3007 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3010 * The last argument must be a non-null pointer of a MonoException* pointer.
3011 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3012 * exception has been thrown in managed code. Otherwise it will point
3013 * to the MonoException* caught by the thunk. In this case, the result of
3014 * the thunk is undefined:
3016 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3017 * MonoException *ex = NULL;
3018 * Equals func = mono_method_get_unmanaged_thunk (method);
3019 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3021 * // handle exception
3024 * The calling convention of the thunk matches the platform's default
3025 * convention. This means that under Windows, C declarations must
3026 * contain the __stdcall attribute:
3028 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3029 * MonoObject*, MonoException**);
3033 * Value type arguments and return values are treated as they were objects:
3035 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3036 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3038 * Arguments must be properly boxed upon trunk's invocation, while return
3039 * values must be unboxed.
3042 mono_method_get_unmanaged_thunk (MonoMethod *method)
3044 MONO_REQ_GC_NEUTRAL_MODE;
3045 MONO_REQ_API_ENTRYPOINT;
3050 g_assert (!mono_threads_is_coop_enabled ());
3052 MONO_ENTER_GC_UNSAFE;
3053 method = mono_marshal_get_thunk_invoke_wrapper (method);
3054 res = mono_compile_method_checked (method, &error);
3055 mono_error_cleanup (&error);
3056 MONO_EXIT_GC_UNSAFE;
3062 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3064 MONO_REQ_GC_UNSAFE_MODE;
3068 /* object fields cannot be byref, so we don't need a
3070 gpointer *p = (gpointer*)dest;
3077 case MONO_TYPE_BOOLEAN:
3079 case MONO_TYPE_U1: {
3080 guint8 *p = (guint8*)dest;
3081 *p = value ? *(guint8*)value : 0;
3086 case MONO_TYPE_CHAR: {
3087 guint16 *p = (guint16*)dest;
3088 *p = value ? *(guint16*)value : 0;
3091 #if SIZEOF_VOID_P == 4
3096 case MONO_TYPE_U4: {
3097 gint32 *p = (gint32*)dest;
3098 *p = value ? *(gint32*)value : 0;
3101 #if SIZEOF_VOID_P == 8
3106 case MONO_TYPE_U8: {
3107 gint64 *p = (gint64*)dest;
3108 *p = value ? *(gint64*)value : 0;
3111 case MONO_TYPE_R4: {
3112 float *p = (float*)dest;
3113 *p = value ? *(float*)value : 0;
3116 case MONO_TYPE_R8: {
3117 double *p = (double*)dest;
3118 *p = value ? *(double*)value : 0;
3121 case MONO_TYPE_STRING:
3122 case MONO_TYPE_SZARRAY:
3123 case MONO_TYPE_CLASS:
3124 case MONO_TYPE_OBJECT:
3125 case MONO_TYPE_ARRAY:
3126 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3128 case MONO_TYPE_FNPTR:
3129 case MONO_TYPE_PTR: {
3130 gpointer *p = (gpointer*)dest;
3131 *p = deref_pointer? *(gpointer*)value: value;
3134 case MONO_TYPE_VALUETYPE:
3135 /* note that 't' and 'type->type' can be different */
3136 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3137 t = mono_class_enum_basetype (type->data.klass)->type;
3140 MonoClass *klass = mono_class_from_mono_type (type);
3141 int size = mono_class_value_size (klass, NULL);
3143 mono_gc_bzero_atomic (dest, size);
3145 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3148 case MONO_TYPE_GENERICINST:
3149 t = type->data.generic_class->container_class->byval_arg.type;
3152 g_error ("got type %x", type->type);
3157 * mono_field_set_value:
3158 * @obj: Instance object
3159 * @field: MonoClassField describing the field to set
3160 * @value: The value to be set
3162 * Sets the value of the field described by @field in the object instance @obj
3163 * to the value passed in @value. This method should only be used for instance
3164 * fields. For static fields, use mono_field_static_set_value.
3166 * The value must be on the native format of the field type.
3169 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3171 MONO_REQ_GC_UNSAFE_MODE;
3175 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3177 dest = (char*)obj + field->offset;
3178 mono_copy_value (field->type, dest, value, FALSE);
3182 * mono_field_static_set_value:
3183 * @field: MonoClassField describing the field to set
3184 * @value: The value to be set
3186 * Sets the value of the static field described by @field
3187 * to the value passed in @value.
3189 * The value must be on the native format of the field type.
3192 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3194 MONO_REQ_GC_UNSAFE_MODE;
3198 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3199 /* you cant set a constant! */
3200 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3202 if (field->offset == -1) {
3203 /* Special static */
3206 mono_domain_lock (vt->domain);
3207 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3208 mono_domain_unlock (vt->domain);
3209 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3211 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3213 mono_copy_value (field->type, dest, value, FALSE);
3217 * mono_vtable_get_static_field_data:
3219 * Internal use function: return a pointer to the memory holding the static fields
3220 * for a class or NULL if there are no static fields.
3221 * This is exported only for use by the debugger.
3224 mono_vtable_get_static_field_data (MonoVTable *vt)
3226 MONO_REQ_GC_NEUTRAL_MODE
3228 if (!vt->has_static_fields)
3230 return vt->vtable [vt->klass->vtable_size];
3234 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3236 MONO_REQ_GC_UNSAFE_MODE;
3240 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3241 if (field->offset == -1) {
3242 /* Special static */
3245 mono_domain_lock (vt->domain);
3246 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3247 mono_domain_unlock (vt->domain);
3248 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3250 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3253 src = (guint8*)obj + field->offset;
3260 * mono_field_get_value:
3261 * @obj: Object instance
3262 * @field: MonoClassField describing the field to fetch information from
3263 * @value: pointer to the location where the value will be stored
3265 * Use this routine to get the value of the field @field in the object
3268 * The pointer provided by value must be of the field type, for reference
3269 * types this is a MonoObject*, for value types its the actual pointer to
3274 * mono_field_get_value (obj, int_field, &i);
3277 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3279 MONO_REQ_GC_UNSAFE_MODE;
3285 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3287 src = (char*)obj + field->offset;
3288 mono_copy_value (field->type, value, src, TRUE);
3292 * mono_field_get_value_object:
3293 * @domain: domain where the object will be created (if boxing)
3294 * @field: MonoClassField describing the field to fetch information from
3295 * @obj: The object instance for the field.
3297 * Returns: a new MonoObject with the value from the given field. If the
3298 * field represents a value type, the value is boxed.
3302 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3305 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3306 mono_error_assert_ok (&error);
3311 * mono_field_get_value_object_checked:
3312 * @domain: domain where the object will be created (if boxing)
3313 * @field: MonoClassField describing the field to fetch information from
3314 * @obj: The object instance for the field.
3315 * @error: Set on error.
3317 * Returns: a new MonoObject with the value from the given field. If the
3318 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3322 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3324 MONO_REQ_GC_UNSAFE_MODE;
3326 mono_error_init (error);
3330 MonoVTable *vtable = NULL;
3332 gboolean is_static = FALSE;
3333 gboolean is_ref = FALSE;
3334 gboolean is_literal = FALSE;
3335 gboolean is_ptr = FALSE;
3336 MonoType *type = mono_field_get_type_checked (field, error);
3338 return_val_if_nok (error, NULL);
3340 switch (type->type) {
3341 case MONO_TYPE_STRING:
3342 case MONO_TYPE_OBJECT:
3343 case MONO_TYPE_CLASS:
3344 case MONO_TYPE_ARRAY:
3345 case MONO_TYPE_SZARRAY:
3350 case MONO_TYPE_BOOLEAN:
3353 case MONO_TYPE_CHAR:
3362 case MONO_TYPE_VALUETYPE:
3363 is_ref = type->byref;
3365 case MONO_TYPE_GENERICINST:
3366 is_ref = !mono_type_generic_inst_is_valuetype (type);
3372 g_error ("type 0x%x not handled in "
3373 "mono_field_get_value_object", type->type);
3377 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3380 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3384 vtable = mono_class_vtable_full (domain, field->parent, error);
3385 return_val_if_nok (error, NULL);
3387 if (!vtable->initialized) {
3388 mono_runtime_class_init_full (vtable, error);
3389 return_val_if_nok (error, NULL);
3398 get_default_field_value (domain, field, &o, error);
3399 return_val_if_nok (error, NULL);
3400 } else if (is_static) {
3401 mono_field_static_get_value_checked (vtable, field, &o, error);
3402 return_val_if_nok (error, NULL);
3404 mono_field_get_value (obj, field, &o);
3410 static MonoMethod *m;
3416 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3417 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3423 get_default_field_value (domain, field, v, error);
3424 return_val_if_nok (error, NULL);
3425 } else if (is_static) {
3426 mono_field_static_get_value_checked (vtable, field, v, error);
3427 return_val_if_nok (error, NULL);
3429 mono_field_get_value (obj, field, v);
3432 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3433 args [0] = ptr ? *ptr : NULL;
3434 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3435 return_val_if_nok (error, NULL);
3437 o = mono_runtime_invoke_checked (m, NULL, args, error);
3438 return_val_if_nok (error, NULL);
3443 /* boxed value type */
3444 klass = mono_class_from_mono_type (type);
3446 if (mono_class_is_nullable (klass))
3447 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3449 o = mono_object_new_checked (domain, klass, error);
3450 return_val_if_nok (error, NULL);
3451 v = ((gchar *) o) + sizeof (MonoObject);
3454 get_default_field_value (domain, field, v, error);
3455 return_val_if_nok (error, NULL);
3456 } else if (is_static) {
3457 mono_field_static_get_value_checked (vtable, field, v, error);
3458 return_val_if_nok (error, NULL);
3460 mono_field_get_value (obj, field, v);
3467 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3469 MONO_REQ_GC_UNSAFE_MODE;
3471 mono_error_init (error);
3473 const char *p = blob;
3474 mono_metadata_decode_blob_size (p, &p);
3477 case MONO_TYPE_BOOLEAN:
3480 *(guint8 *) value = *p;
3482 case MONO_TYPE_CHAR:
3485 *(guint16*) value = read16 (p);
3489 *(guint32*) value = read32 (p);
3493 *(guint64*) value = read64 (p);
3496 readr4 (p, (float*) value);
3499 readr8 (p, (double*) value);
3501 case MONO_TYPE_STRING:
3502 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3504 case MONO_TYPE_CLASS:
3505 *(gpointer*) value = NULL;
3509 g_warning ("type 0x%02x should not be in constant table", type);
3515 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3517 MONO_REQ_GC_NEUTRAL_MODE;
3519 MonoTypeEnum def_type;
3522 mono_error_init (error);
3524 data = mono_class_get_field_default_value (field, &def_type);
3525 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3529 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3531 MONO_REQ_GC_UNSAFE_MODE;
3535 mono_error_init (error);
3537 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3539 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3540 get_default_field_value (vt->domain, field, value, error);
3544 if (field->offset == -1) {
3545 /* Special static */
3546 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3547 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3549 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3551 mono_copy_value (field->type, value, src, TRUE);
3555 * mono_field_static_get_value:
3556 * @vt: vtable to the object
3557 * @field: MonoClassField describing the field to fetch information from
3558 * @value: where the value is returned
3560 * Use this routine to get the value of the static field @field value.
3562 * The pointer provided by value must be of the field type, for reference
3563 * types this is a MonoObject*, for value types its the actual pointer to
3568 * mono_field_static_get_value (vt, int_field, &i);
3571 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3573 MONO_REQ_GC_NEUTRAL_MODE;
3576 mono_field_static_get_value_checked (vt, field, value, &error);
3577 mono_error_cleanup (&error);
3581 * mono_field_static_get_value_checked:
3582 * @vt: vtable to the object
3583 * @field: MonoClassField describing the field to fetch information from
3584 * @value: where the value is returned
3585 * @error: set on error
3587 * Use this routine to get the value of the static field @field value.
3589 * The pointer provided by value must be of the field type, for reference
3590 * types this is a MonoObject*, for value types its the actual pointer to
3595 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3596 * if (!is_ok (error)) { ... }
3598 * On failure sets @error.
3601 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3603 MONO_REQ_GC_NEUTRAL_MODE;
3605 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3609 * mono_property_set_value:
3610 * @prop: MonoProperty to set
3611 * @obj: instance object on which to act
3612 * @params: parameters to pass to the propery
3613 * @exc: optional exception
3615 * Invokes the property's set method with the given arguments on the
3616 * object instance obj (or NULL for static properties).
3618 * You can pass NULL as the exc argument if you don't want to
3619 * catch exceptions, otherwise, *exc will be set to the exception
3620 * thrown, if any. if an exception is thrown, you can't use the
3621 * MonoObject* result from the function.
3624 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3626 MONO_REQ_GC_UNSAFE_MODE;
3629 do_runtime_invoke (prop->set, obj, params, exc, &error);
3630 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3631 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3633 mono_error_cleanup (&error);
3638 * mono_property_set_value_checked:
3639 * @prop: MonoProperty to set
3640 * @obj: instance object on which to act
3641 * @params: parameters to pass to the propery
3642 * @error: set on error
3644 * Invokes the property's set method with the given arguments on the
3645 * object instance obj (or NULL for static properties).
3647 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3648 * If an exception is thrown, it will be caught and returned via @error.
3651 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3653 MONO_REQ_GC_UNSAFE_MODE;
3657 mono_error_init (error);
3658 do_runtime_invoke (prop->set, obj, params, &exc, error);
3659 if (exc != NULL && is_ok (error))
3660 mono_error_set_exception_instance (error, (MonoException*)exc);
3661 return is_ok (error);
3665 * mono_property_get_value:
3666 * @prop: MonoProperty to fetch
3667 * @obj: instance object on which to act
3668 * @params: parameters to pass to the propery
3669 * @exc: optional exception
3671 * Invokes the property's get method with the given arguments on the
3672 * object instance obj (or NULL for static properties).
3674 * You can pass NULL as the exc argument if you don't want to
3675 * catch exceptions, otherwise, *exc will be set to the exception
3676 * thrown, if any. if an exception is thrown, you can't use the
3677 * MonoObject* result from the function.
3679 * Returns: the value from invoking the get method on the property.
3682 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3684 MONO_REQ_GC_UNSAFE_MODE;
3687 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3688 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3689 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3691 mono_error_cleanup (&error); /* FIXME don't raise here */
3698 * mono_property_get_value_checked:
3699 * @prop: MonoProperty to fetch
3700 * @obj: instance object on which to act
3701 * @params: parameters to pass to the propery
3702 * @error: set on error
3704 * Invokes the property's get method with the given arguments on the
3705 * object instance obj (or NULL for static properties).
3707 * If an exception is thrown, you can't use the
3708 * MonoObject* result from the function. The exception will be propagated via @error.
3710 * Returns: the value from invoking the get method on the property. On
3711 * failure returns NULL and sets @error.
3714 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3716 MONO_REQ_GC_UNSAFE_MODE;
3719 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3720 if (exc != NULL && !is_ok (error))
3721 mono_error_set_exception_instance (error, (MonoException*) exc);
3729 * mono_nullable_init:
3730 * @buf: The nullable structure to initialize.
3731 * @value: the value to initialize from
3732 * @klass: the type for the object
3734 * Initialize the nullable structure pointed to by @buf from @value which
3735 * should be a boxed value type. The size of @buf should be able to hold
3736 * as much data as the @klass->instance_size (which is the number of bytes
3737 * that will be copies).
3739 * Since Nullables have variable structure, we can not define a C
3740 * structure for them.
3743 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3745 MONO_REQ_GC_UNSAFE_MODE;
3747 MonoClass *param_class = klass->cast_class;
3749 mono_class_setup_fields (klass);
3750 g_assert (klass->fields_inited);
3752 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3753 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3755 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3757 if (param_class->has_references)
3758 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3760 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3762 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3767 * mono_nullable_box:
3768 * @buf: The buffer representing the data to be boxed
3769 * @klass: the type to box it as.
3770 * @error: set on oerr
3772 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3773 * @buf. On failure returns NULL and sets @error
3776 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3778 MONO_REQ_GC_UNSAFE_MODE;
3780 mono_error_init (error);
3781 MonoClass *param_class = klass->cast_class;
3783 mono_class_setup_fields (klass);
3784 g_assert (klass->fields_inited);
3786 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3787 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3789 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3790 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3791 return_val_if_nok (error, NULL);
3792 if (param_class->has_references)
3793 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3795 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3803 * mono_get_delegate_invoke:
3804 * @klass: The delegate class
3806 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3809 mono_get_delegate_invoke (MonoClass *klass)
3811 MONO_REQ_GC_NEUTRAL_MODE;
3815 /* This is called at runtime, so avoid the slower search in metadata */
3816 mono_class_setup_methods (klass);
3817 if (mono_class_has_failure (klass))
3819 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3824 * mono_get_delegate_begin_invoke:
3825 * @klass: The delegate class
3827 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3830 mono_get_delegate_begin_invoke (MonoClass *klass)
3832 MONO_REQ_GC_NEUTRAL_MODE;
3836 /* This is called at runtime, so avoid the slower search in metadata */
3837 mono_class_setup_methods (klass);
3838 if (mono_class_has_failure (klass))
3840 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3845 * mono_get_delegate_end_invoke:
3846 * @klass: The delegate class
3848 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3851 mono_get_delegate_end_invoke (MonoClass *klass)
3853 MONO_REQ_GC_NEUTRAL_MODE;
3857 /* This is called at runtime, so avoid the slower search in metadata */
3858 mono_class_setup_methods (klass);
3859 if (mono_class_has_failure (klass))
3861 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3866 * mono_runtime_delegate_invoke:
3867 * @delegate: pointer to a delegate object.
3868 * @params: parameters for the delegate.
3869 * @exc: Pointer to the exception result.
3871 * Invokes the delegate method @delegate with the parameters provided.
3873 * You can pass NULL as the exc argument if you don't want to
3874 * catch exceptions, otherwise, *exc will be set to the exception
3875 * thrown, if any. if an exception is thrown, you can't use the
3876 * MonoObject* result from the function.
3879 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3881 MONO_REQ_GC_UNSAFE_MODE;
3885 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3887 mono_error_cleanup (&error);
3890 if (!is_ok (&error))
3891 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3895 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3896 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3902 * mono_runtime_delegate_try_invoke:
3903 * @delegate: pointer to a delegate object.
3904 * @params: parameters for the delegate.
3905 * @exc: Pointer to the exception result.
3906 * @error: set on error
3908 * Invokes the delegate method @delegate with the parameters provided.
3910 * You can pass NULL as the exc argument if you don't want to
3911 * catch exceptions, otherwise, *exc will be set to the exception
3912 * thrown, if any. On failure to execute, @error will be set.
3913 * if an exception is thrown, you can't use the
3914 * MonoObject* result from the function.
3917 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3919 MONO_REQ_GC_UNSAFE_MODE;
3921 mono_error_init (error);
3923 MonoClass *klass = delegate->vtable->klass;
3926 im = mono_get_delegate_invoke (klass);
3928 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3931 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3933 o = mono_runtime_invoke_checked (im, delegate, params, error);
3940 * mono_runtime_delegate_invoke_checked:
3941 * @delegate: pointer to a delegate object.
3942 * @params: parameters for the delegate.
3943 * @error: set on error
3945 * Invokes the delegate method @delegate with the parameters provided.
3947 * On failure @error will be set and you can't use the MonoObject*
3948 * result from the function.
3951 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3953 mono_error_init (error);
3954 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3957 static char **main_args = NULL;
3958 static int num_main_args = 0;
3961 * mono_runtime_get_main_args:
3963 * Returns: a MonoArray with the arguments passed to the main program
3966 mono_runtime_get_main_args (void)
3968 MONO_REQ_GC_UNSAFE_MODE;
3970 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3971 mono_error_assert_ok (&error);
3976 * mono_runtime_get_main_args:
3977 * @error: set on error
3979 * Returns: a MonoArray with the arguments passed to the main
3980 * program. On failure returns NULL and sets @error.
3983 mono_runtime_get_main_args_checked (MonoError *error)
3987 MonoDomain *domain = mono_domain_get ();
3989 mono_error_init (error);
3991 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3992 return_val_if_nok (error, NULL);
3994 for (i = 0; i < num_main_args; ++i)
3995 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4001 free_main_args (void)
4003 MONO_REQ_GC_NEUTRAL_MODE;
4007 for (i = 0; i < num_main_args; ++i)
4008 g_free (main_args [i]);
4015 * mono_runtime_set_main_args:
4016 * @argc: number of arguments from the command line
4017 * @argv: array of strings from the command line
4019 * Set the command line arguments from an embedding application that doesn't otherwise call
4020 * mono_runtime_run_main ().
4023 mono_runtime_set_main_args (int argc, char* argv[])
4025 MONO_REQ_GC_NEUTRAL_MODE;
4030 main_args = g_new0 (char*, argc);
4031 num_main_args = argc;
4033 for (i = 0; i < argc; ++i) {
4036 utf8_arg = mono_utf8_from_external (argv[i]);
4037 if (utf8_arg == NULL) {
4038 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4039 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4043 main_args [i] = utf8_arg;
4050 * Prepare an array of arguments in order to execute a standard Main()
4051 * method (argc/argv contains the executable name). This method also
4052 * sets the command line argument value needed by System.Environment.
4056 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4058 MONO_REQ_GC_UNSAFE_MODE;
4062 MonoArray *args = NULL;
4063 MonoDomain *domain = mono_domain_get ();
4064 gchar *utf8_fullpath;
4065 MonoMethodSignature *sig;
4067 g_assert (method != NULL);
4069 mono_thread_set_main (mono_thread_current ());
4071 main_args = g_new0 (char*, argc);
4072 num_main_args = argc;
4074 if (!g_path_is_absolute (argv [0])) {
4075 gchar *basename = g_path_get_basename (argv [0]);
4076 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4080 utf8_fullpath = mono_utf8_from_external (fullpath);
4081 if(utf8_fullpath == NULL) {
4082 /* Printing the arg text will cause glib to
4083 * whinge about "Invalid UTF-8", but at least
4084 * its relevant, and shows the problem text
4087 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4088 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4095 utf8_fullpath = mono_utf8_from_external (argv[0]);
4096 if(utf8_fullpath == NULL) {
4097 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4098 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4103 main_args [0] = utf8_fullpath;
4105 for (i = 1; i < argc; ++i) {
4108 utf8_arg=mono_utf8_from_external (argv[i]);
4109 if(utf8_arg==NULL) {
4110 /* Ditto the comment about Invalid UTF-8 here */
4111 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4112 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4116 main_args [i] = utf8_arg;
4121 sig = mono_method_signature (method);
4123 g_print ("Unable to load Main method.\n");
4127 if (sig->param_count) {
4128 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4129 mono_error_assert_ok (&error);
4130 for (i = 0; i < argc; ++i) {
4131 /* The encodings should all work, given that
4132 * we've checked all these args for the
4135 gchar *str = mono_utf8_from_external (argv [i]);
4136 MonoString *arg = mono_string_new (domain, str);
4137 mono_array_setref (args, i, arg);
4141 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4142 mono_error_assert_ok (&error);
4145 mono_assembly_set_main (method->klass->image->assembly);
4151 * mono_runtime_run_main:
4152 * @method: the method to start the application with (usually Main)
4153 * @argc: number of arguments from the command line
4154 * @argv: array of strings from the command line
4155 * @exc: excetption results
4157 * Execute a standard Main() method (argc/argv contains the
4158 * executable name). This method also sets the command line argument value
4159 * needed by System.Environment.
4164 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4167 MONO_REQ_GC_UNSAFE_MODE;
4170 MonoArray *args = prepare_run_main (method, argc, argv);
4173 res = mono_runtime_try_exec_main (method, args, exc);
4175 res = mono_runtime_exec_main_checked (method, args, &error);
4176 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4182 * mono_runtime_run_main_checked:
4183 * @method: the method to start the application with (usually Main)
4184 * @argc: number of arguments from the command line
4185 * @argv: array of strings from the command line
4186 * @error: set on error
4188 * Execute a standard Main() method (argc/argv contains the
4189 * executable name). This method also sets the command line argument value
4190 * needed by System.Environment. On failure sets @error.
4195 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4198 mono_error_init (error);
4199 MonoArray *args = prepare_run_main (method, argc, argv);
4200 return mono_runtime_exec_main_checked (method, args, error);
4204 * mono_runtime_try_run_main:
4205 * @method: the method to start the application with (usually Main)
4206 * @argc: number of arguments from the command line
4207 * @argv: array of strings from the command line
4208 * @exc: set if Main throws an exception
4209 * @error: set if Main can't be executed
4211 * Execute a standard Main() method (argc/argv contains the executable
4212 * name). This method also sets the command line argument value needed
4213 * by System.Environment. On failure sets @error if Main can't be
4214 * executed or @exc if it threw and exception.
4219 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4223 MonoArray *args = prepare_run_main (method, argc, argv);
4224 return mono_runtime_try_exec_main (method, args, exc);
4229 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4231 static MonoMethod *serialize_method;
4237 if (!serialize_method) {
4238 MonoClass *klass = mono_class_get_remoting_services_class ();
4239 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4242 if (!serialize_method) {
4247 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4252 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4253 if (*exc == NULL && !mono_error_ok (&error))
4254 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4256 mono_error_cleanup (&error);
4265 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4267 MONO_REQ_GC_UNSAFE_MODE;
4269 static MonoMethod *deserialize_method;
4275 if (!deserialize_method) {
4276 MonoClass *klass = mono_class_get_remoting_services_class ();
4277 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4279 if (!deserialize_method) {
4287 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4288 if (*exc == NULL && !mono_error_ok (&error))
4289 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4291 mono_error_cleanup (&error);
4299 #ifndef DISABLE_REMOTING
4301 make_transparent_proxy (MonoObject *obj, MonoError *error)
4303 MONO_REQ_GC_UNSAFE_MODE;
4305 static MonoMethod *get_proxy_method;
4307 MonoDomain *domain = mono_domain_get ();
4308 MonoRealProxy *real_proxy;
4309 MonoReflectionType *reflection_type;
4310 MonoTransparentProxy *transparent_proxy;
4312 mono_error_init (error);
4314 if (!get_proxy_method)
4315 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4317 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4319 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4320 return_val_if_nok (error, NULL);
4321 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4322 return_val_if_nok (error, NULL);
4324 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4325 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4327 MonoObject *exc = NULL;
4329 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4330 if (exc != NULL && is_ok (error))
4331 mono_error_set_exception_instance (error, (MonoException*)exc);
4333 return (MonoObject*) transparent_proxy;
4335 #endif /* DISABLE_REMOTING */
4338 * mono_object_xdomain_representation
4340 * @target_domain: a domain
4341 * @error: set on error.
4343 * Creates a representation of obj in the domain target_domain. This
4344 * is either a copy of obj arrived through via serialization and
4345 * deserialization or a proxy, depending on whether the object is
4346 * serializable or marshal by ref. obj must not be in target_domain.
4348 * If the object cannot be represented in target_domain, NULL is
4349 * returned and @error is set appropriately.
4352 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4354 MONO_REQ_GC_UNSAFE_MODE;
4356 mono_error_init (error);
4357 MonoObject *deserialized = NULL;
4359 #ifndef DISABLE_REMOTING
4360 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4361 deserialized = make_transparent_proxy (obj, error);
4366 gboolean failure = FALSE;
4367 MonoDomain *domain = mono_domain_get ();
4368 MonoObject *serialized;
4369 MonoObject *exc = NULL;
4371 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4372 serialized = serialize_object (obj, &failure, &exc);
4373 mono_domain_set_internal_with_options (target_domain, FALSE);
4375 deserialized = deserialize_object (serialized, &failure, &exc);
4376 if (domain != target_domain)
4377 mono_domain_set_internal_with_options (domain, FALSE);
4379 mono_error_set_exception_instance (error, (MonoException*)exc);
4382 return deserialized;
4385 /* Used in call_unhandled_exception_delegate */
4387 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4389 MONO_REQ_GC_UNSAFE_MODE;
4391 mono_error_init (error);
4394 MonoMethod *method = NULL;
4395 MonoBoolean is_terminating = TRUE;
4398 klass = mono_class_get_unhandled_exception_event_args_class ();
4399 mono_class_init (klass);
4401 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4402 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4406 args [1] = &is_terminating;
4408 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4409 return_val_if_nok (error, NULL);
4411 mono_runtime_invoke_checked (method, obj, args, error);
4412 return_val_if_nok (error, NULL);
4417 /* Used in mono_unhandled_exception */
4419 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4420 MONO_REQ_GC_UNSAFE_MODE;
4423 MonoObject *e = NULL;
4425 MonoDomain *current_domain = mono_domain_get ();
4427 if (domain != current_domain)
4428 mono_domain_set_internal_with_options (domain, FALSE);
4430 g_assert (domain == mono_object_domain (domain->domain));
4432 if (mono_object_domain (exc) != domain) {
4434 exc = mono_object_xdomain_representation (exc, domain, &error);
4436 if (!is_ok (&error)) {
4437 MonoError inner_error;
4438 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4439 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4440 mono_error_assert_ok (&inner_error);
4442 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4443 "System.Runtime.Serialization", "SerializationException",
4444 "Could not serialize unhandled exception.");
4448 g_assert (mono_object_domain (exc) == domain);
4450 pa [0] = domain->domain;
4451 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4452 mono_error_assert_ok (&error);
4453 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4454 if (!is_ok (&error)) {
4456 e = (MonoObject*)mono_error_convert_to_exception (&error);
4458 mono_error_cleanup (&error);
4461 if (domain != current_domain)
4462 mono_domain_set_internal_with_options (current_domain, FALSE);
4465 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4466 if (!mono_error_ok (&error)) {
4467 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4468 mono_error_cleanup (&error);
4470 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4476 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4479 * mono_runtime_unhandled_exception_policy_set:
4480 * @policy: the new policy
4482 * This is a VM internal routine.
4484 * Sets the runtime policy for handling unhandled exceptions.
4487 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4488 runtime_unhandled_exception_policy = policy;
4492 * mono_runtime_unhandled_exception_policy_get:
4494 * This is a VM internal routine.
4496 * Gets the runtime policy for handling unhandled exceptions.
4498 MonoRuntimeUnhandledExceptionPolicy
4499 mono_runtime_unhandled_exception_policy_get (void) {
4500 return runtime_unhandled_exception_policy;
4504 * mono_unhandled_exception:
4505 * @exc: exception thrown
4507 * This is a VM internal routine.
4509 * We call this function when we detect an unhandled exception
4510 * in the default domain.
4512 * It invokes the * UnhandledException event in AppDomain or prints
4513 * a warning to the console
4516 mono_unhandled_exception (MonoObject *exc)
4518 MONO_REQ_GC_UNSAFE_MODE;
4521 MonoClassField *field;
4522 MonoDomain *current_domain, *root_domain;
4523 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4525 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4528 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4531 current_domain = mono_domain_get ();
4532 root_domain = mono_get_root_domain ();
4534 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4535 mono_error_assert_ok (&error);
4536 if (current_domain != root_domain) {
4537 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4538 mono_error_assert_ok (&error);
4541 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4542 mono_print_unhandled_exception (exc);
4544 /* unhandled exception callbacks must not be aborted */
4545 mono_threads_begin_abort_protected_block ();
4546 if (root_appdomain_delegate)
4547 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4548 if (current_appdomain_delegate)
4549 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4550 mono_threads_end_abort_protected_block ();
4553 /* set exitcode only if we will abort the process */
4554 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4555 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4557 mono_environment_exitcode_set (1);
4562 * mono_runtime_exec_managed_code:
4563 * @domain: Application domain
4564 * @main_func: function to invoke from the execution thread
4565 * @main_args: parameter to the main_func
4567 * Launch a new thread to execute a function
4569 * main_func is called back from the thread with main_args as the
4570 * parameter. The callback function is expected to start Main()
4571 * eventually. This function then waits for all managed threads to
4573 * It is not necesseray anymore to execute managed code in a subthread,
4574 * so this function should not be used anymore by default: just
4575 * execute the code and then call mono_thread_manage ().
4578 mono_runtime_exec_managed_code (MonoDomain *domain,
4579 MonoMainThreadFunc main_func,
4583 mono_thread_create_checked (domain, main_func, main_args, &error);
4584 mono_error_assert_ok (&error);
4586 mono_thread_manage ();
4590 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4592 MonoInternalThread* thread = mono_thread_internal_current ();
4593 MonoCustomAttrInfo* cinfo;
4594 gboolean has_stathread_attribute;
4596 if (!domain->entry_assembly) {
4598 MonoAssembly *assembly;
4600 assembly = method->klass->image->assembly;
4601 domain->entry_assembly = assembly;
4602 /* Domains created from another domain already have application_base and configuration_file set */
4603 if (domain->setup->application_base == NULL) {
4604 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4607 if (domain->setup->configuration_file == NULL) {
4608 str = g_strconcat (assembly->image->name, ".config", NULL);
4609 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4611 mono_domain_set_options_from_config (domain);
4615 MonoError cattr_error;
4616 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4617 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4619 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4621 mono_custom_attrs_free (cinfo);
4623 has_stathread_attribute = FALSE;
4625 if (has_stathread_attribute) {
4626 thread->apartment_state = ThreadApartmentState_STA;
4628 thread->apartment_state = ThreadApartmentState_MTA;
4630 mono_thread_init_apartment_state ();
4635 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4637 MONO_REQ_GC_UNSAFE_MODE;
4642 mono_error_init (error);
4647 /* FIXME: check signature of method */
4648 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4650 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4652 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4655 mono_environment_exitcode_set (rval);
4657 mono_runtime_invoke_checked (method, NULL, pa, error);
4669 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4671 MONO_REQ_GC_UNSAFE_MODE;
4681 /* FIXME: check signature of method */
4682 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4683 MonoError inner_error;
4685 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4686 if (*exc == NULL && !mono_error_ok (&inner_error))
4687 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4689 mono_error_cleanup (&inner_error);
4692 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4696 mono_environment_exitcode_set (rval);
4698 MonoError inner_error;
4699 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4700 if (*exc == NULL && !mono_error_ok (&inner_error))
4701 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4703 mono_error_cleanup (&inner_error);
4708 /* If the return type of Main is void, only
4709 * set the exitcode if an exception was thrown
4710 * (we don't want to blow away an
4711 * explicitly-set exit code)
4714 mono_environment_exitcode_set (rval);
4722 * Execute a standard Main() method (args doesn't contain the
4726 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4729 prepare_thread_to_exec_main (mono_object_domain (args), method);
4731 int rval = do_try_exec_main (method, args, exc);
4734 int rval = do_exec_main_checked (method, args, &error);
4735 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4741 * Execute a standard Main() method (args doesn't contain the
4744 * On failure sets @error
4747 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4749 mono_error_init (error);
4750 prepare_thread_to_exec_main (mono_object_domain (args), method);
4751 return do_exec_main_checked (method, args, error);
4755 * Execute a standard Main() method (args doesn't contain the
4758 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4761 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4763 prepare_thread_to_exec_main (mono_object_domain (args), method);
4764 return do_try_exec_main (method, args, exc);
4769 /** invoke_array_extract_argument:
4770 * @params: array of arguments to the method.
4771 * @i: the index of the argument to extract.
4772 * @t: ith type from the method signature.
4773 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4774 * @error: set on error.
4776 * Given an array of method arguments, return the ith one using the corresponding type
4777 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4779 * On failure sets @error and returns NULL.
4782 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4784 MonoType *t_orig = t;
4785 gpointer result = NULL;
4786 mono_error_init (error);
4791 case MONO_TYPE_BOOLEAN:
4794 case MONO_TYPE_CHAR:
4803 case MONO_TYPE_VALUETYPE:
4804 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4805 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4806 result = mono_array_get (params, MonoObject*, i);
4808 *has_byref_nullables = TRUE;
4810 /* MS seems to create the objects if a null is passed in */
4811 if (!mono_array_get (params, MonoObject*, i)) {
4812 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4813 return_val_if_nok (error, NULL);
4814 mono_array_setref (params, i, o);
4819 * We can't pass the unboxed vtype byref to the callee, since
4820 * that would mean the callee would be able to modify boxed
4821 * primitive types. So we (and MS) make a copy of the boxed
4822 * object, pass that to the callee, and replace the original
4823 * boxed object in the arg array with the copy.
4825 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4826 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4827 return_val_if_nok (error, NULL);
4828 mono_array_setref (params, i, copy);
4831 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4834 case MONO_TYPE_STRING:
4835 case MONO_TYPE_OBJECT:
4836 case MONO_TYPE_CLASS:
4837 case MONO_TYPE_ARRAY:
4838 case MONO_TYPE_SZARRAY:
4840 result = mono_array_addr (params, MonoObject*, i);
4841 // FIXME: I need to check this code path
4843 result = mono_array_get (params, MonoObject*, i);
4845 case MONO_TYPE_GENERICINST:
4847 t = &t->data.generic_class->container_class->this_arg;
4849 t = &t->data.generic_class->container_class->byval_arg;
4851 case MONO_TYPE_PTR: {
4854 /* The argument should be an IntPtr */
4855 arg = mono_array_get (params, MonoObject*, i);
4859 g_assert (arg->vtable->klass == mono_defaults.int_class);
4860 result = ((MonoIntPtr*)arg)->m_value;
4865 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4870 * mono_runtime_invoke_array:
4871 * @method: method to invoke
4872 * @obJ: object instance
4873 * @params: arguments to the method
4874 * @exc: exception information.
4876 * Invokes the method represented by @method on the object @obj.
4878 * obj is the 'this' pointer, it should be NULL for static
4879 * methods, a MonoObject* for object instances and a pointer to
4880 * the value type for value types.
4882 * The params array contains the arguments to the method with the
4883 * same convention: MonoObject* pointers for object instances and
4884 * pointers to the value type otherwise. The _invoke_array
4885 * variant takes a C# object[] as the params argument (MonoArray
4886 * *params): in this case the value types are boxed inside the
4887 * respective reference representation.
4889 * From unmanaged code you'll usually use the
4890 * mono_runtime_invoke_checked() variant.
4892 * Note that this function doesn't handle virtual methods for
4893 * you, it will exec the exact method you pass: we still need to
4894 * expose a function to lookup the derived class implementation
4895 * of a virtual method (there are examples of this in the code,
4898 * You can pass NULL as the exc argument if you don't want to
4899 * catch exceptions, otherwise, *exc will be set to the exception
4900 * thrown, if any. if an exception is thrown, you can't use the
4901 * MonoObject* result from the function.
4903 * If the method returns a value type, it is boxed in an object
4907 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4912 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4914 mono_error_cleanup (&error);
4917 if (!is_ok (&error))
4918 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4922 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4923 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4929 * mono_runtime_invoke_array_checked:
4930 * @method: method to invoke
4931 * @obJ: object instance
4932 * @params: arguments to the method
4933 * @error: set on failure.
4935 * Invokes the method represented by @method on the object @obj.
4937 * obj is the 'this' pointer, it should be NULL for static
4938 * methods, a MonoObject* for object instances and a pointer to
4939 * the value type for value types.
4941 * The params array contains the arguments to the method with the
4942 * same convention: MonoObject* pointers for object instances and
4943 * pointers to the value type otherwise. The _invoke_array
4944 * variant takes a C# object[] as the params argument (MonoArray
4945 * *params): in this case the value types are boxed inside the
4946 * respective reference representation.
4948 * From unmanaged code you'll usually use the
4949 * mono_runtime_invoke_checked() variant.
4951 * Note that this function doesn't handle virtual methods for
4952 * you, it will exec the exact method you pass: we still need to
4953 * expose a function to lookup the derived class implementation
4954 * of a virtual method (there are examples of this in the code,
4957 * On failure or exception, @error will be set. In that case, you
4958 * can't use the MonoObject* result from the function.
4960 * If the method returns a value type, it is boxed in an object
4964 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4967 mono_error_init (error);
4968 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4972 * mono_runtime_try_invoke_array:
4973 * @method: method to invoke
4974 * @obJ: object instance
4975 * @params: arguments to the method
4976 * @exc: exception information.
4977 * @error: set on failure.
4979 * Invokes the method represented by @method on the object @obj.
4981 * obj is the 'this' pointer, it should be NULL for static
4982 * methods, a MonoObject* for object instances and a pointer to
4983 * the value type for value types.
4985 * The params array contains the arguments to the method with the
4986 * same convention: MonoObject* pointers for object instances and
4987 * pointers to the value type otherwise. The _invoke_array
4988 * variant takes a C# object[] as the params argument (MonoArray
4989 * *params): in this case the value types are boxed inside the
4990 * respective reference representation.
4992 * From unmanaged code you'll usually use the
4993 * mono_runtime_invoke_checked() variant.
4995 * Note that this function doesn't handle virtual methods for
4996 * you, it will exec the exact method you pass: we still need to
4997 * expose a function to lookup the derived class implementation
4998 * of a virtual method (there are examples of this in the code,
5001 * You can pass NULL as the exc argument if you don't want to catch
5002 * exceptions, otherwise, *exc will be set to the exception thrown, if
5003 * any. On other failures, @error will be set. If an exception is
5004 * thrown or there's an error, you can't use the MonoObject* result
5005 * from the function.
5007 * If the method returns a value type, it is boxed in an object
5011 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5012 MonoObject **exc, MonoError *error)
5014 MONO_REQ_GC_UNSAFE_MODE;
5016 mono_error_init (error);
5018 MonoMethodSignature *sig = mono_method_signature (method);
5019 gpointer *pa = NULL;
5022 gboolean has_byref_nullables = FALSE;
5024 if (NULL != params) {
5025 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5026 for (i = 0; i < mono_array_length (params); i++) {
5027 MonoType *t = sig->params [i];
5028 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5029 return_val_if_nok (error, NULL);
5033 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5036 if (mono_class_is_nullable (method->klass)) {
5037 /* Need to create a boxed vtype instead */
5043 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5048 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5049 mono_error_assert_ok (error);
5050 g_assert (obj); /*maybe we should raise a TLE instead?*/
5051 #ifndef DISABLE_REMOTING
5052 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5053 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5056 if (method->klass->valuetype)
5057 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5060 } else if (method->klass->valuetype) {
5061 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5062 return_val_if_nok (error, NULL);
5066 mono_runtime_try_invoke (method, o, pa, exc, error);
5068 mono_runtime_invoke_checked (method, o, pa, error);
5071 return (MonoObject *)obj;
5073 if (mono_class_is_nullable (method->klass)) {
5074 MonoObject *nullable;
5076 /* Convert the unboxed vtype into a Nullable structure */
5077 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5078 return_val_if_nok (error, NULL);
5080 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5081 return_val_if_nok (error, NULL);
5082 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5083 obj = mono_object_unbox (nullable);
5086 /* obj must be already unboxed if needed */
5088 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5090 res = mono_runtime_invoke_checked (method, obj, pa, error);
5092 return_val_if_nok (error, NULL);
5094 if (sig->ret->type == MONO_TYPE_PTR) {
5095 MonoClass *pointer_class;
5096 static MonoMethod *box_method;
5098 MonoObject *box_exc;
5101 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5102 * convert it to a Pointer object.
5104 pointer_class = mono_class_get_pointer_class ();
5106 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5108 g_assert (res->vtable->klass == mono_defaults.int_class);
5109 box_args [0] = ((MonoIntPtr*)res)->m_value;
5110 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5111 return_val_if_nok (error, NULL);
5113 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5114 g_assert (box_exc == NULL);
5115 mono_error_assert_ok (error);
5118 if (has_byref_nullables) {
5120 * The runtime invoke wrapper already converted byref nullables back,
5121 * and stored them in pa, we just need to copy them back to the
5124 for (i = 0; i < mono_array_length (params); i++) {
5125 MonoType *t = sig->params [i];
5127 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5128 mono_array_setref (params, i, pa [i]);
5138 * @klass: the class of the object that we want to create
5140 * Returns: a newly created object whose definition is
5141 * looked up using @klass. This will not invoke any constructors,
5142 * so the consumer of this routine has to invoke any constructors on
5143 * its own to initialize the object.
5145 * It returns NULL on failure.
5148 mono_object_new (MonoDomain *domain, MonoClass *klass)
5150 MONO_REQ_GC_UNSAFE_MODE;
5154 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5156 mono_error_cleanup (&error);
5161 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5163 MONO_REQ_GC_UNSAFE_MODE;
5167 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5169 mono_error_set_pending_exception (&error);
5174 * mono_object_new_checked:
5175 * @klass: the class of the object that we want to create
5176 * @error: set on error
5178 * Returns: a newly created object whose definition is
5179 * looked up using @klass. This will not invoke any constructors,
5180 * so the consumer of this routine has to invoke any constructors on
5181 * its own to initialize the object.
5183 * It returns NULL on failure and sets @error.
5186 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5188 MONO_REQ_GC_UNSAFE_MODE;
5192 vtable = mono_class_vtable (domain, klass);
5193 g_assert (vtable); /* FIXME don't swallow the error */
5195 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5200 * mono_object_new_pinned:
5202 * Same as mono_object_new, but the returned object will be pinned.
5203 * For SGEN, these objects will only be freed at appdomain unload.
5206 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5208 MONO_REQ_GC_UNSAFE_MODE;
5212 mono_error_init (error);
5214 vtable = mono_class_vtable (domain, klass);
5215 g_assert (vtable); /* FIXME don't swallow the error */
5217 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5219 if (G_UNLIKELY (!o))
5220 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5221 else if (G_UNLIKELY (vtable->klass->has_finalize))
5222 mono_object_register_finalizer (o);
5228 * mono_object_new_specific:
5229 * @vtable: the vtable of the object that we want to create
5231 * Returns: A newly created object with class and domain specified
5235 mono_object_new_specific (MonoVTable *vtable)
5238 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5239 mono_error_cleanup (&error);
5245 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5247 MONO_REQ_GC_UNSAFE_MODE;
5251 mono_error_init (error);
5253 /* check for is_com_object for COM Interop */
5254 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5257 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5260 MonoClass *klass = mono_class_get_activation_services_class ();
5263 mono_class_init (klass);
5265 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5267 mono_error_set_not_supported (error, "Linked away.");
5270 vtable->domain->create_proxy_for_type_method = im;
5273 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5274 if (!mono_error_ok (error))
5277 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5278 if (!mono_error_ok (error))
5285 return mono_object_new_alloc_specific_checked (vtable, error);
5289 ves_icall_object_new_specific (MonoVTable *vtable)
5292 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5293 mono_error_set_pending_exception (&error);
5299 * mono_object_new_alloc_specific:
5300 * @vtable: virtual table for the object.
5302 * This function allocates a new `MonoObject` with the type derived
5303 * from the @vtable information. If the class of this object has a
5304 * finalizer, then the object will be tracked for finalization.
5306 * This method might raise an exception on errors. Use the
5307 * `mono_object_new_fast_checked` method if you want to manually raise
5310 * Returns: the allocated object.
5313 mono_object_new_alloc_specific (MonoVTable *vtable)
5316 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5317 mono_error_cleanup (&error);
5323 * mono_object_new_alloc_specific_checked:
5324 * @vtable: virtual table for the object.
5325 * @error: holds the error return value.
5327 * This function allocates a new `MonoObject` with the type derived
5328 * from the @vtable information. If the class of this object has a
5329 * finalizer, then the object will be tracked for finalization.
5331 * If there is not enough memory, the @error parameter will be set
5332 * and will contain a user-visible message with the amount of bytes
5333 * that were requested.
5335 * Returns: the allocated object, or NULL if there is not enough memory
5339 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5341 MONO_REQ_GC_UNSAFE_MODE;
5345 mono_error_init (error);
5347 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5349 if (G_UNLIKELY (!o))
5350 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5351 else if (G_UNLIKELY (vtable->klass->has_finalize))
5352 mono_object_register_finalizer (o);
5358 * mono_object_new_fast:
5359 * @vtable: virtual table for the object.
5361 * This function allocates a new `MonoObject` with the type derived
5362 * from the @vtable information. The returned object is not tracked
5363 * for finalization. If your object implements a finalizer, you should
5364 * use `mono_object_new_alloc_specific` instead.
5366 * This method might raise an exception on errors. Use the
5367 * `mono_object_new_fast_checked` method if you want to manually raise
5370 * Returns: the allocated object.
5373 mono_object_new_fast (MonoVTable *vtable)
5376 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5377 mono_error_cleanup (&error);
5383 * mono_object_new_fast_checked:
5384 * @vtable: virtual table for the object.
5385 * @error: holds the error return value.
5387 * This function allocates a new `MonoObject` with the type derived
5388 * from the @vtable information. The returned object is not tracked
5389 * for finalization. If your object implements a finalizer, you should
5390 * use `mono_object_new_alloc_specific_checked` instead.
5392 * If there is not enough memory, the @error parameter will be set
5393 * and will contain a user-visible message with the amount of bytes
5394 * that were requested.
5396 * Returns: the allocated object, or NULL if there is not enough memory
5400 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5402 MONO_REQ_GC_UNSAFE_MODE;
5406 mono_error_init (error);
5408 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5410 if (G_UNLIKELY (!o))
5411 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5417 ves_icall_object_new_fast (MonoVTable *vtable)
5420 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5421 mono_error_set_pending_exception (&error);
5427 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5429 MONO_REQ_GC_UNSAFE_MODE;
5433 mono_error_init (error);
5435 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5437 if (G_UNLIKELY (!o))
5438 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5439 else if (G_UNLIKELY (vtable->klass->has_finalize))
5440 mono_object_register_finalizer (o);
5446 * mono_class_get_allocation_ftn:
5448 * @for_box: the object will be used for boxing
5449 * @pass_size_in_words:
5451 * Return the allocation function appropriate for the given class.
5455 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5457 MONO_REQ_GC_NEUTRAL_MODE;
5459 *pass_size_in_words = FALSE;
5461 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5462 return ves_icall_object_new_specific;
5464 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5466 return ves_icall_object_new_fast;
5469 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5470 * of the overhead of parameter passing.
5473 *pass_size_in_words = TRUE;
5474 #ifdef GC_REDIRECT_TO_LOCAL
5475 return GC_local_gcj_fast_malloc;
5477 return GC_gcj_fast_malloc;
5482 return ves_icall_object_new_specific;
5486 * mono_object_new_from_token:
5487 * @image: Context where the type_token is hosted
5488 * @token: a token of the type that we want to create
5490 * Returns: A newly created object whose definition is
5491 * looked up using @token in the @image image
5494 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5496 MONO_REQ_GC_UNSAFE_MODE;
5502 klass = mono_class_get_checked (image, token, &error);
5503 mono_error_assert_ok (&error);
5505 result = mono_object_new_checked (domain, klass, &error);
5507 mono_error_cleanup (&error);
5514 * mono_object_clone:
5515 * @obj: the object to clone
5517 * Returns: A newly created object who is a shallow copy of @obj
5520 mono_object_clone (MonoObject *obj)
5523 MonoObject *o = mono_object_clone_checked (obj, &error);
5524 mono_error_cleanup (&error);
5530 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5532 MONO_REQ_GC_UNSAFE_MODE;
5537 mono_error_init (error);
5539 size = obj->vtable->klass->instance_size;
5541 if (obj->vtable->klass->rank)
5542 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5544 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5546 if (G_UNLIKELY (!o)) {
5547 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5551 /* If the object doesn't contain references this will do a simple memmove. */
5552 mono_gc_wbarrier_object_copy (o, obj);
5554 if (obj->vtable->klass->has_finalize)
5555 mono_object_register_finalizer (o);
5560 * mono_array_full_copy:
5561 * @src: source array to copy
5562 * @dest: destination array
5564 * Copies the content of one array to another with exactly the same type and size.
5567 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5569 MONO_REQ_GC_UNSAFE_MODE;
5572 MonoClass *klass = src->obj.vtable->klass;
5574 g_assert (klass == dest->obj.vtable->klass);
5576 size = mono_array_length (src);
5577 g_assert (size == mono_array_length (dest));
5578 size *= mono_array_element_size (klass);
5580 if (klass->element_class->valuetype) {
5581 if (klass->element_class->has_references)
5582 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5584 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5586 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5589 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5594 * mono_array_clone_in_domain:
5595 * @domain: the domain in which the array will be cloned into
5596 * @array: the array to clone
5597 * @error: set on error
5599 * This routine returns a copy of the array that is hosted on the
5600 * specified MonoDomain. On failure returns NULL and sets @error.
5603 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5605 MONO_REQ_GC_UNSAFE_MODE;
5610 MonoClass *klass = array->obj.vtable->klass;
5612 mono_error_init (error);
5614 if (array->bounds == NULL) {
5615 size = mono_array_length (array);
5616 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5617 return_val_if_nok (error, NULL);
5619 size *= mono_array_element_size (klass);
5621 if (klass->element_class->valuetype) {
5622 if (klass->element_class->has_references)
5623 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5625 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5627 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5630 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5635 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5636 size = mono_array_element_size (klass);
5637 for (i = 0; i < klass->rank; ++i) {
5638 sizes [i] = array->bounds [i].length;
5639 size *= array->bounds [i].length;
5640 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5642 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5643 return_val_if_nok (error, NULL);
5645 if (klass->element_class->valuetype) {
5646 if (klass->element_class->has_references)
5647 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5649 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5651 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5654 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5662 * @array: the array to clone
5664 * Returns: A newly created array who is a shallow copy of @array
5667 mono_array_clone (MonoArray *array)
5669 MONO_REQ_GC_UNSAFE_MODE;
5672 MonoArray *result = mono_array_clone_checked (array, &error);
5673 mono_error_cleanup (&error);
5678 * mono_array_clone_checked:
5679 * @array: the array to clone
5680 * @error: set on error
5682 * Returns: A newly created array who is a shallow copy of @array. On
5683 * failure returns NULL and sets @error.
5686 mono_array_clone_checked (MonoArray *array, MonoError *error)
5689 MONO_REQ_GC_UNSAFE_MODE;
5690 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5693 /* helper macros to check for overflow when calculating the size of arrays */
5694 #ifdef MONO_BIG_ARRAYS
5695 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5696 #define MYGUINT_MAX MYGUINT64_MAX
5697 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5698 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5699 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5700 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5701 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5703 #define MYGUINT32_MAX 4294967295U
5704 #define MYGUINT_MAX MYGUINT32_MAX
5705 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5706 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5707 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5708 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5709 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5713 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5715 MONO_REQ_GC_NEUTRAL_MODE;
5719 byte_len = mono_array_element_size (klass);
5720 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5723 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5725 byte_len += MONO_SIZEOF_MONO_ARRAY;
5733 * mono_array_new_full:
5734 * @domain: domain where the object is created
5735 * @array_class: array class
5736 * @lengths: lengths for each dimension in the array
5737 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5739 * This routine creates a new array objects with the given dimensions,
5740 * lower bounds and type.
5743 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5746 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5747 mono_error_cleanup (&error);
5753 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5755 MONO_REQ_GC_UNSAFE_MODE;
5757 uintptr_t byte_len = 0, len, bounds_size;
5760 MonoArrayBounds *bounds;
5764 mono_error_init (error);
5766 if (!array_class->inited)
5767 mono_class_init (array_class);
5771 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5772 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5774 if (len > MONO_ARRAY_MAX_INDEX) {
5775 mono_error_set_generic_error (error, "System", "OverflowException", "");
5780 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5782 for (i = 0; i < array_class->rank; ++i) {
5783 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5784 mono_error_set_generic_error (error, "System", "OverflowException", "");
5787 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5788 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5795 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5796 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5802 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5803 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5806 byte_len = (byte_len + 3) & ~3;
5807 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5808 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5811 byte_len += bounds_size;
5814 * Following three lines almost taken from mono_object_new ():
5815 * they need to be kept in sync.
5817 vtable = mono_class_vtable_full (domain, array_class, error);
5818 return_val_if_nok (error, NULL);
5821 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5823 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5825 if (G_UNLIKELY (!o)) {
5826 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5830 array = (MonoArray*)o;
5832 bounds = array->bounds;
5835 for (i = 0; i < array_class->rank; ++i) {
5836 bounds [i].length = lengths [i];
5838 bounds [i].lower_bound = lower_bounds [i];
5847 * @domain: domain where the object is created
5848 * @eclass: element class
5849 * @n: number of array elements
5851 * This routine creates a new szarray with @n elements of type @eclass.
5854 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5856 MONO_REQ_GC_UNSAFE_MODE;
5859 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5860 mono_error_cleanup (&error);
5865 * mono_array_new_checked:
5866 * @domain: domain where the object is created
5867 * @eclass: element class
5868 * @n: number of array elements
5869 * @error: set on error
5871 * This routine creates a new szarray with @n elements of type @eclass.
5872 * On failure returns NULL and sets @error.
5875 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5879 mono_error_init (error);
5881 ac = mono_array_class_get (eclass, 1);
5884 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5885 return_val_if_nok (error, NULL);
5887 return mono_array_new_specific_checked (vtable, n, error);
5891 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5894 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5895 mono_error_set_pending_exception (&error);
5901 * mono_array_new_specific:
5902 * @vtable: a vtable in the appropriate domain for an initialized class
5903 * @n: number of array elements
5905 * This routine is a fast alternative to mono_array_new() for code which
5906 * can be sure about the domain it operates in.
5909 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5912 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5913 mono_error_cleanup (&error);
5919 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5921 MONO_REQ_GC_UNSAFE_MODE;
5926 mono_error_init (error);
5928 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5929 mono_error_set_generic_error (error, "System", "OverflowException", "");
5933 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5934 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5937 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5939 if (G_UNLIKELY (!o)) {
5940 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5944 return (MonoArray*)o;
5948 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5951 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5952 mono_error_set_pending_exception (&error);
5958 * mono_string_new_utf16:
5959 * @text: a pointer to an utf16 string
5960 * @len: the length of the string
5962 * Returns: A newly created string object which contains @text.
5965 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5967 MONO_REQ_GC_UNSAFE_MODE;
5970 MonoString *res = NULL;
5971 res = mono_string_new_utf16_checked (domain, text, len, &error);
5972 mono_error_cleanup (&error);
5978 * mono_string_new_utf16_checked:
5979 * @text: a pointer to an utf16 string
5980 * @len: the length of the string
5981 * @error: written on error.
5983 * Returns: A newly created string object which contains @text.
5984 * On error, returns NULL and sets @error.
5987 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5989 MONO_REQ_GC_UNSAFE_MODE;
5993 mono_error_init (error);
5995 s = mono_string_new_size_checked (domain, len, error);
5997 memcpy (mono_string_chars (s), text, len * 2);
6003 * mono_string_new_utf32:
6004 * @text: a pointer to an utf32 string
6005 * @len: the length of the string
6006 * @error: set on failure.
6008 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6011 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6013 MONO_REQ_GC_UNSAFE_MODE;
6016 mono_unichar2 *utf16_output = NULL;
6017 gint32 utf16_len = 0;
6018 GError *gerror = NULL;
6019 glong items_written;
6021 mono_error_init (error);
6022 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6025 g_error_free (gerror);
6027 while (utf16_output [utf16_len]) utf16_len++;
6029 s = mono_string_new_size_checked (domain, utf16_len, error);
6030 return_val_if_nok (error, NULL);
6032 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6034 g_free (utf16_output);
6040 * mono_string_new_utf32:
6041 * @text: a pointer to an utf32 string
6042 * @len: the length of the string
6044 * Returns: A newly created string object which contains @text.
6047 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6050 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6051 mono_error_cleanup (&error);
6056 * mono_string_new_size:
6057 * @text: a pointer to an utf16 string
6058 * @len: the length of the string
6060 * Returns: A newly created string object of @len
6063 mono_string_new_size (MonoDomain *domain, gint32 len)
6066 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6067 mono_error_cleanup (&error);
6073 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6075 MONO_REQ_GC_UNSAFE_MODE;
6081 mono_error_init (error);
6083 /* check for overflow */
6084 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6085 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6089 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6090 g_assert (size > 0);
6092 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6095 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6097 if (G_UNLIKELY (!s)) {
6098 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6106 * mono_string_new_len:
6107 * @text: a pointer to an utf8 string
6108 * @length: number of bytes in @text to consider
6110 * Returns: A newly created string object which contains @text.
6113 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6115 MONO_REQ_GC_UNSAFE_MODE;
6118 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6119 mono_error_cleanup (&error);
6124 * mono_string_new_len_checked:
6125 * @text: a pointer to an utf8 string
6126 * @length: number of bytes in @text to consider
6127 * @error: set on error
6129 * Returns: A newly created string object which contains @text. On
6130 * failure returns NULL and sets @error.
6133 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6135 MONO_REQ_GC_UNSAFE_MODE;
6137 mono_error_init (error);
6139 GError *eg_error = NULL;
6140 MonoString *o = NULL;
6142 glong items_written;
6144 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6147 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6149 g_error_free (eg_error);
6158 * @text: a pointer to an utf8 string
6160 * Returns: A newly created string object which contains @text.
6162 * This function asserts if it cannot allocate a new string.
6164 * @deprecated Use mono_string_new_checked in new code.
6167 mono_string_new (MonoDomain *domain, const char *text)
6170 MonoString *res = NULL;
6171 res = mono_string_new_checked (domain, text, &error);
6172 mono_error_assert_ok (&error);
6177 * mono_string_new_checked:
6178 * @text: a pointer to an utf8 string
6179 * @merror: set on error
6181 * Returns: A newly created string object which contains @text.
6182 * On error returns NULL and sets @merror.
6185 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6187 MONO_REQ_GC_UNSAFE_MODE;
6189 GError *eg_error = NULL;
6190 MonoString *o = NULL;
6192 glong items_written;
6195 mono_error_init (error);
6199 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6202 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6204 g_error_free (eg_error);
6208 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6213 MonoString *o = NULL;
6215 if (!g_utf8_validate (text, -1, &end)) {
6216 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6220 len = g_utf8_strlen (text, -1);
6221 o = mono_string_new_size_checked (domain, len, error);
6224 str = mono_string_chars (o);
6226 while (text < end) {
6227 *str++ = g_utf8_get_char (text);
6228 text = g_utf8_next_char (text);
6237 * mono_string_new_wrapper:
6238 * @text: pointer to utf8 characters.
6240 * Helper function to create a string object from @text in the current domain.
6243 mono_string_new_wrapper (const char *text)
6245 MONO_REQ_GC_UNSAFE_MODE;
6247 MonoDomain *domain = mono_domain_get ();
6250 return mono_string_new (domain, text);
6257 * @class: the class of the value
6258 * @value: a pointer to the unboxed data
6260 * Returns: A newly created object which contains @value.
6263 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6266 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6267 mono_error_cleanup (&error);
6272 * mono_value_box_checked:
6273 * @domain: the domain of the new object
6274 * @class: the class of the value
6275 * @value: a pointer to the unboxed data
6276 * @error: set on error
6278 * Returns: A newly created object which contains @value. On failure
6279 * returns NULL and sets @error.
6282 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6284 MONO_REQ_GC_UNSAFE_MODE;
6289 mono_error_init (error);
6291 g_assert (klass->valuetype);
6292 if (mono_class_is_nullable (klass))
6293 return mono_nullable_box ((guint8 *)value, klass, error);
6295 vtable = mono_class_vtable (domain, klass);
6298 size = mono_class_instance_size (klass);
6299 res = mono_object_new_alloc_specific_checked (vtable, error);
6300 return_val_if_nok (error, NULL);
6302 size = size - sizeof (MonoObject);
6305 g_assert (size == mono_class_value_size (klass, NULL));
6306 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6308 #if NO_UNALIGNED_ACCESS
6309 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6313 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6316 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6319 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6322 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6325 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6329 if (klass->has_finalize) {
6330 mono_object_register_finalizer (res);
6331 return_val_if_nok (error, NULL);
6338 * @dest: destination pointer
6339 * @src: source pointer
6340 * @klass: a valuetype class
6342 * Copy a valuetype from @src to @dest. This function must be used
6343 * when @klass contains references fields.
6346 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6348 MONO_REQ_GC_UNSAFE_MODE;
6350 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6354 * mono_value_copy_array:
6355 * @dest: destination array
6356 * @dest_idx: index in the @dest array
6357 * @src: source pointer
6358 * @count: number of items
6360 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6361 * This function must be used when @klass contains references fields.
6362 * Overlap is handled.
6365 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6367 MONO_REQ_GC_UNSAFE_MODE;
6369 int size = mono_array_element_size (dest->obj.vtable->klass);
6370 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6371 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6372 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6376 * mono_object_get_domain:
6377 * @obj: object to query
6379 * Returns: the MonoDomain where the object is hosted
6382 mono_object_get_domain (MonoObject *obj)
6384 MONO_REQ_GC_UNSAFE_MODE;
6386 return mono_object_domain (obj);
6390 * mono_object_get_class:
6391 * @obj: object to query
6393 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6395 * Returns: the MonoClass of the object.
6398 mono_object_get_class (MonoObject *obj)
6400 MONO_REQ_GC_UNSAFE_MODE;
6402 return mono_object_class (obj);
6405 * mono_object_get_size:
6406 * @o: object to query
6408 * Returns: the size, in bytes, of @o
6411 mono_object_get_size (MonoObject* o)
6413 MONO_REQ_GC_UNSAFE_MODE;
6415 MonoClass* klass = mono_object_class (o);
6416 if (klass == mono_defaults.string_class) {
6417 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6418 } else if (o->vtable->rank) {
6419 MonoArray *array = (MonoArray*)o;
6420 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6421 if (array->bounds) {
6424 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6428 return mono_class_instance_size (klass);
6433 * mono_object_unbox:
6434 * @obj: object to unbox
6436 * Returns: a pointer to the start of the valuetype boxed in this
6439 * This method will assert if the object passed is not a valuetype.
6442 mono_object_unbox (MonoObject *obj)
6444 MONO_REQ_GC_UNSAFE_MODE;
6446 /* add assert for valuetypes? */
6447 g_assert (obj->vtable->klass->valuetype);
6448 return ((char*)obj) + sizeof (MonoObject);
6452 * mono_object_isinst:
6454 * @klass: a pointer to a class
6456 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6459 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6461 MONO_REQ_GC_UNSAFE_MODE;
6464 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6465 mono_error_cleanup (&error);
6471 * mono_object_isinst_checked:
6473 * @klass: a pointer to a class
6474 * @error: set on error
6476 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6477 * On failure returns NULL and sets @error.
6480 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6482 MONO_REQ_GC_UNSAFE_MODE;
6484 mono_error_init (error);
6486 MonoObject *result = NULL;
6489 mono_class_init (klass);
6491 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6492 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6499 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6503 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6505 MONO_REQ_GC_UNSAFE_MODE;
6508 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6509 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6514 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6516 MONO_REQ_GC_UNSAFE_MODE;
6520 mono_error_init (error);
6527 if (mono_class_is_interface (klass)) {
6528 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6532 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6533 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6536 MonoClass *oklass = vt->klass;
6537 if (mono_class_is_transparent_proxy (oklass))
6538 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6540 mono_class_setup_supertypes (klass);
6541 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6544 #ifndef DISABLE_REMOTING
6545 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6547 MonoDomain *domain = mono_domain_get ();
6549 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6550 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6551 MonoMethod *im = NULL;
6554 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6556 mono_error_set_not_supported (error, "Linked away.");
6559 im = mono_object_get_virtual_method (rp, im);
6562 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6563 return_val_if_nok (error, NULL);
6566 res = mono_runtime_invoke_checked (im, rp, pa, error);
6567 return_val_if_nok (error, NULL);
6569 if (*(MonoBoolean *) mono_object_unbox(res)) {
6570 /* Update the vtable of the remote type, so it can safely cast to this new type */
6571 mono_upgrade_remote_class (domain, obj, klass, error);
6572 return_val_if_nok (error, NULL);
6576 #endif /* DISABLE_REMOTING */
6581 * mono_object_castclass_mbyref:
6583 * @klass: a pointer to a class
6585 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6588 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6590 MONO_REQ_GC_UNSAFE_MODE;
6593 if (!obj) return NULL;
6594 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6595 mono_error_cleanup (&error);
6600 MonoDomain *orig_domain;
6606 str_lookup (MonoDomain *domain, gpointer user_data)
6608 MONO_REQ_GC_UNSAFE_MODE;
6610 LDStrInfo *info = (LDStrInfo *)user_data;
6611 if (info->res || domain == info->orig_domain)
6613 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6617 mono_string_get_pinned (MonoString *str, MonoError *error)
6619 MONO_REQ_GC_UNSAFE_MODE;
6621 mono_error_init (error);
6623 /* We only need to make a pinned version of a string if this is a moving GC */
6624 if (!mono_gc_is_moving ())
6628 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6629 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6631 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6632 news->length = mono_string_length (str);
6634 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6640 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6642 MONO_REQ_GC_UNSAFE_MODE;
6644 MonoGHashTable *ldstr_table;
6645 MonoString *s, *res;
6648 mono_error_init (error);
6650 domain = ((MonoObject *)str)->vtable->domain;
6651 ldstr_table = domain->ldstr_table;
6653 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6659 /* Allocate outside the lock */
6661 s = mono_string_get_pinned (str, error);
6662 return_val_if_nok (error, NULL);
6665 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6670 mono_g_hash_table_insert (ldstr_table, s, s);
6675 LDStrInfo ldstr_info;
6676 ldstr_info.orig_domain = domain;
6677 ldstr_info.ins = str;
6678 ldstr_info.res = NULL;
6680 mono_domain_foreach (str_lookup, &ldstr_info);
6681 if (ldstr_info.res) {
6683 * the string was already interned in some other domain:
6684 * intern it in the current one as well.
6686 mono_g_hash_table_insert (ldstr_table, str, str);
6696 * mono_string_is_interned:
6697 * @o: String to probe
6699 * Returns whether the string has been interned.
6702 mono_string_is_interned (MonoString *o)
6705 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6706 /* This function does not fail. */
6707 mono_error_assert_ok (&error);
6712 * mono_string_intern:
6713 * @o: String to intern
6715 * Interns the string passed.
6716 * Returns: The interned string.
6719 mono_string_intern (MonoString *str)
6722 MonoString *result = mono_string_intern_checked (str, &error);
6723 mono_error_assert_ok (&error);
6728 * mono_string_intern_checked:
6729 * @o: String to intern
6730 * @error: set on error.
6732 * Interns the string passed.
6733 * Returns: The interned string. On failure returns NULL and sets @error
6736 mono_string_intern_checked (MonoString *str, MonoError *error)
6738 MONO_REQ_GC_UNSAFE_MODE;
6740 mono_error_init (error);
6742 return mono_string_is_interned_lookup (str, TRUE, error);
6747 * @domain: the domain where the string will be used.
6748 * @image: a metadata context
6749 * @idx: index into the user string table.
6751 * Implementation for the ldstr opcode.
6752 * Returns: a loaded string from the @image/@idx combination.
6755 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6758 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6759 mono_error_cleanup (&error);
6764 * mono_ldstr_checked:
6765 * @domain: the domain where the string will be used.
6766 * @image: a metadata context
6767 * @idx: index into the user string table.
6768 * @error: set on error.
6770 * Implementation for the ldstr opcode.
6771 * Returns: a loaded string from the @image/@idx combination.
6772 * On failure returns NULL and sets @error.
6775 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6777 MONO_REQ_GC_UNSAFE_MODE;
6778 mono_error_init (error);
6780 if (image->dynamic) {
6781 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6784 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6785 return NULL; /*FIXME we should probably be raising an exception here*/
6786 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6792 * mono_ldstr_metadata_sig
6793 * @domain: the domain for the string
6794 * @sig: the signature of a metadata string
6795 * @error: set on error
6797 * Returns: a MonoString for a string stored in the metadata. On
6798 * failure returns NULL and sets @error.
6801 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6803 MONO_REQ_GC_UNSAFE_MODE;
6805 mono_error_init (error);
6806 const char *str = sig;
6807 MonoString *o, *interned;
6810 len2 = mono_metadata_decode_blob_size (str, &str);
6813 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6814 return_val_if_nok (error, NULL);
6815 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6818 guint16 *p2 = (guint16*)mono_string_chars (o);
6819 for (i = 0; i < len2; ++i) {
6820 *p2 = GUINT16_FROM_LE (*p2);
6826 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6829 return interned; /* o will get garbage collected */
6831 o = mono_string_get_pinned (o, error);
6834 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6836 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6848 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6852 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6858 GError *gerror = NULL;
6860 mono_error_init (error);
6862 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6863 return NULL; /*FIXME we should probably be raising an exception here*/
6864 str = mono_metadata_user_string (image, idx);
6866 len2 = mono_metadata_decode_blob_size (str, &str);
6869 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6871 mono_error_set_argument (error, "string", "%s", gerror->message);
6872 g_error_free (gerror);
6875 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6876 if (len2 > written) {
6877 /* allocate the total length and copy the part of the string that has been converted */
6878 char *as2 = (char *)g_malloc0 (len2);
6879 memcpy (as2, as, written);
6888 * mono_string_to_utf8:
6889 * @s: a System.String
6891 * Returns the UTF8 representation for @s.
6892 * The resulting buffer needs to be freed with mono_free().
6894 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6897 mono_string_to_utf8 (MonoString *s)
6899 MONO_REQ_GC_UNSAFE_MODE;
6902 char *result = mono_string_to_utf8_checked (s, &error);
6904 if (!is_ok (&error)) {
6905 mono_error_cleanup (&error);
6912 * mono_string_to_utf8_checked:
6913 * @s: a System.String
6914 * @error: a MonoError.
6916 * Converts a MonoString to its UTF8 representation. May fail; check
6917 * @error to determine whether the conversion was successful.
6918 * The resulting buffer should be freed with mono_free().
6921 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6923 MONO_REQ_GC_UNSAFE_MODE;
6927 GError *gerror = NULL;
6929 mono_error_init (error);
6935 return g_strdup ("");
6937 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6939 mono_error_set_argument (error, "string", "%s", gerror->message);
6940 g_error_free (gerror);
6943 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6944 if (s->length > written) {
6945 /* allocate the total length and copy the part of the string that has been converted */
6946 char *as2 = (char *)g_malloc0 (s->length);
6947 memcpy (as2, as, written);
6956 * mono_string_to_utf8_ignore:
6959 * Converts a MonoString to its UTF8 representation. Will ignore
6960 * invalid surrogate pairs.
6961 * The resulting buffer should be freed with mono_free().
6965 mono_string_to_utf8_ignore (MonoString *s)
6967 MONO_REQ_GC_UNSAFE_MODE;
6976 return g_strdup ("");
6978 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6980 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6981 if (s->length > written) {
6982 /* allocate the total length and copy the part of the string that has been converted */
6983 char *as2 = (char *)g_malloc0 (s->length);
6984 memcpy (as2, as, written);
6993 * mono_string_to_utf8_image_ignore:
6994 * @s: a System.String
6996 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6999 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7001 MONO_REQ_GC_UNSAFE_MODE;
7003 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7007 * mono_string_to_utf8_mp_ignore:
7008 * @s: a System.String
7010 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7013 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7015 MONO_REQ_GC_UNSAFE_MODE;
7017 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7022 * mono_string_to_utf16:
7025 * Return an null-terminated array of the utf-16 chars
7026 * contained in @s. The result must be freed with g_free().
7027 * This is a temporary helper until our string implementation
7028 * is reworked to always include the null terminating char.
7031 mono_string_to_utf16 (MonoString *s)
7033 MONO_REQ_GC_UNSAFE_MODE;
7040 as = (char *)g_malloc ((s->length * 2) + 2);
7041 as [(s->length * 2)] = '\0';
7042 as [(s->length * 2) + 1] = '\0';
7045 return (gunichar2 *)(as);
7048 memcpy (as, mono_string_chars(s), s->length * 2);
7049 return (gunichar2 *)(as);
7053 * mono_string_to_utf32:
7056 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7057 * contained in @s. The result must be freed with g_free().
7060 mono_string_to_utf32 (MonoString *s)
7062 MONO_REQ_GC_UNSAFE_MODE;
7064 mono_unichar4 *utf32_output = NULL;
7065 GError *error = NULL;
7066 glong items_written;
7071 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7074 g_error_free (error);
7076 return utf32_output;
7080 * mono_string_from_utf16:
7081 * @data: the UTF16 string (LPWSTR) to convert
7083 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7085 * Returns: a MonoString.
7088 mono_string_from_utf16 (gunichar2 *data)
7091 MonoString *result = mono_string_from_utf16_checked (data, &error);
7092 mono_error_cleanup (&error);
7097 * mono_string_from_utf16_checked:
7098 * @data: the UTF16 string (LPWSTR) to convert
7099 * @error: set on error
7101 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7103 * Returns: a MonoString. On failure sets @error and returns NULL.
7106 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7109 MONO_REQ_GC_UNSAFE_MODE;
7111 mono_error_init (error);
7112 MonoDomain *domain = mono_domain_get ();
7118 while (data [len]) len++;
7120 return mono_string_new_utf16_checked (domain, data, len, error);
7124 * mono_string_from_utf32:
7125 * @data: the UTF32 string (LPWSTR) to convert
7127 * Converts a UTF32 (UCS-4)to a MonoString.
7129 * Returns: a MonoString.
7132 mono_string_from_utf32 (mono_unichar4 *data)
7135 MonoString *result = mono_string_from_utf32_checked (data, &error);
7136 mono_error_cleanup (&error);
7141 * mono_string_from_utf32_checked:
7142 * @data: the UTF32 string (LPWSTR) to convert
7143 * @error: set on error
7145 * Converts a UTF32 (UCS-4)to a MonoString.
7147 * Returns: a MonoString. On failure returns NULL and sets @error.
7150 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7152 MONO_REQ_GC_UNSAFE_MODE;
7154 mono_error_init (error);
7155 MonoString* result = NULL;
7156 mono_unichar2 *utf16_output = NULL;
7157 GError *gerror = NULL;
7158 glong items_written;
7164 while (data [len]) len++;
7166 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7169 g_error_free (gerror);
7171 result = mono_string_from_utf16_checked (utf16_output, error);
7172 g_free (utf16_output);
7177 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7179 MONO_REQ_GC_UNSAFE_MODE;
7186 r = mono_string_to_utf8_ignore (s);
7188 r = mono_string_to_utf8_checked (s, error);
7189 if (!mono_error_ok (error))
7196 len = strlen (r) + 1;
7198 mp_s = (char *)mono_mempool_alloc (mp, len);
7200 mp_s = (char *)mono_image_alloc (image, len);
7202 memcpy (mp_s, r, len);
7210 * mono_string_to_utf8_image:
7211 * @s: a System.String
7213 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7216 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7218 MONO_REQ_GC_UNSAFE_MODE;
7220 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7224 * mono_string_to_utf8_mp:
7225 * @s: a System.String
7227 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7230 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7232 MONO_REQ_GC_UNSAFE_MODE;
7234 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7238 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7241 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7243 eh_callbacks = *cbs;
7246 MonoRuntimeExceptionHandlingCallbacks *
7247 mono_get_eh_callbacks (void)
7249 return &eh_callbacks;
7253 * mono_raise_exception:
7254 * @ex: exception object
7256 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7259 mono_raise_exception (MonoException *ex)
7261 MONO_REQ_GC_UNSAFE_MODE;
7264 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7265 * that will cause gcc to omit the function epilog, causing problems when
7266 * the JIT tries to walk the stack, since the return address on the stack
7267 * will point into the next function in the executable, not this one.
7269 eh_callbacks.mono_raise_exception (ex);
7273 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7275 MONO_REQ_GC_UNSAFE_MODE;
7277 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7281 * mono_wait_handle_new:
7282 * @domain: Domain where the object will be created
7283 * @handle: Handle for the wait handle
7284 * @error: set on error.
7286 * Returns: A new MonoWaitHandle created in the given domain for the
7287 * given handle. On failure returns NULL and sets @rror.
7290 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7292 MONO_REQ_GC_UNSAFE_MODE;
7294 MonoWaitHandle *res;
7295 gpointer params [1];
7296 static MonoMethod *handle_set;
7298 mono_error_init (error);
7299 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7300 return_val_if_nok (error, NULL);
7302 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7304 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7306 params [0] = &handle;
7308 mono_runtime_invoke_checked (handle_set, res, params, error);
7313 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7315 MONO_REQ_GC_UNSAFE_MODE;
7317 static MonoClassField *f_safe_handle = NULL;
7320 if (!f_safe_handle) {
7321 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7322 g_assert (f_safe_handle);
7325 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7331 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7333 MONO_REQ_GC_UNSAFE_MODE;
7335 RuntimeInvokeFunction runtime_invoke;
7337 mono_error_init (error);
7339 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7340 MonoMethod *method = mono_get_context_capture_method ();
7341 MonoMethod *wrapper;
7344 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7345 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7346 return_val_if_nok (error, NULL);
7347 domain->capture_context_method = mono_compile_method_checked (method, error);
7348 return_val_if_nok (error, NULL);
7351 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7353 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7356 * mono_async_result_new:
7357 * @domain:domain where the object will be created.
7358 * @handle: wait handle.
7359 * @state: state to pass to AsyncResult
7360 * @data: C closure data.
7361 * @error: set on error.
7363 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7364 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7365 * On failure returns NULL and sets @error.
7369 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7371 MONO_REQ_GC_UNSAFE_MODE;
7373 mono_error_init (error);
7374 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7375 return_val_if_nok (error, NULL);
7376 MonoObject *context = mono_runtime_capture_context (domain, error);
7377 return_val_if_nok (error, NULL);
7378 /* we must capture the execution context from the original thread */
7380 MONO_OBJECT_SETREF (res, execution_context, context);
7381 /* note: result may be null if the flow is suppressed */
7384 res->data = (void **)data;
7385 MONO_OBJECT_SETREF (res, object_data, object_data);
7386 MONO_OBJECT_SETREF (res, async_state, state);
7387 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7388 return_val_if_nok (error, NULL);
7390 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7392 res->sync_completed = FALSE;
7393 res->completed = FALSE;
7399 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7401 MONO_REQ_GC_UNSAFE_MODE;
7408 g_assert (ares->async_delegate);
7410 ac = (MonoAsyncCall*) ares->object_data;
7412 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7413 if (mono_error_set_pending_exception (&error))
7416 gpointer wait_event = NULL;
7418 ac->msg->exc = NULL;
7420 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7422 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7423 mono_threads_begin_abort_protected_block ();
7425 if (!ac->msg->exc) {
7426 MonoException *ex = mono_error_convert_to_exception (&error);
7427 ac->msg->exc = (MonoObject *)ex;
7429 mono_error_cleanup (&error);
7432 MONO_OBJECT_SETREF (ac, res, res);
7434 mono_monitor_enter ((MonoObject*) ares);
7435 ares->completed = 1;
7437 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7438 mono_monitor_exit ((MonoObject*) ares);
7440 if (wait_event != NULL)
7441 mono_w32event_set (wait_event);
7443 mono_error_init (&error); //the else branch would leave it in an undefined state
7445 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7447 mono_threads_end_abort_protected_block ();
7449 if (mono_error_set_pending_exception (&error))
7457 mono_message_init (MonoDomain *domain,
7458 MonoMethodMessage *this_obj,
7459 MonoReflectionMethod *method,
7460 MonoArray *out_args,
7463 MONO_REQ_GC_UNSAFE_MODE;
7465 static MonoMethod *init_message_method = NULL;
7467 if (!init_message_method) {
7468 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7469 g_assert (init_message_method != NULL);
7472 mono_error_init (error);
7473 /* FIXME set domain instead? */
7474 g_assert (domain == mono_domain_get ());
7481 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7482 return is_ok (error);
7485 #ifndef DISABLE_REMOTING
7487 * mono_remoting_invoke:
7488 * @real_proxy: pointer to a RealProxy object
7489 * @msg: The MonoMethodMessage to execute
7490 * @exc: used to store exceptions
7491 * @out_args: used to store output arguments
7493 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7494 * IMessage interface and it is not trivial to extract results from there. So
7495 * we call an helper method PrivateInvoke instead of calling
7496 * RealProxy::Invoke() directly.
7498 * Returns: the result object.
7501 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7503 MONO_REQ_GC_UNSAFE_MODE;
7506 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7511 mono_error_init (error);
7513 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7516 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7518 mono_error_set_not_supported (error, "Linked away.");
7521 real_proxy->vtable->domain->private_invoke_method = im;
7524 pa [0] = real_proxy;
7529 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7530 return_val_if_nok (error, NULL);
7537 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7538 MonoObject **exc, MonoArray **out_args, MonoError *error)
7540 MONO_REQ_GC_UNSAFE_MODE;
7542 static MonoClass *object_array_klass;
7543 mono_error_init (error);
7547 MonoMethodSignature *sig;
7549 int i, j, outarg_count = 0;
7551 #ifndef DISABLE_REMOTING
7552 if (target && mono_object_is_transparent_proxy (target)) {
7553 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7554 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7555 target = tp->rp->unwrapped_server;
7557 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7562 domain = mono_domain_get ();
7563 method = msg->method->method;
7564 sig = mono_method_signature (method);
7566 for (i = 0; i < sig->param_count; i++) {
7567 if (sig->params [i]->byref)
7571 if (!object_array_klass) {
7574 klass = mono_array_class_get (mono_defaults.object_class, 1);
7577 mono_memory_barrier ();
7578 object_array_klass = klass;
7581 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7582 return_val_if_nok (error, NULL);
7584 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7587 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7588 return_val_if_nok (error, NULL);
7590 for (i = 0, j = 0; i < sig->param_count; i++) {
7591 if (sig->params [i]->byref) {
7593 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7594 mono_array_setref (*out_args, j, arg);
7603 * prepare_to_string_method:
7605 * @target: Set to @obj or unboxed value if a valuetype
7607 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7610 prepare_to_string_method (MonoObject *obj, void **target)
7612 MONO_REQ_GC_UNSAFE_MODE;
7614 static MonoMethod *to_string = NULL;
7622 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7624 method = mono_object_get_virtual_method (obj, to_string);
7626 // Unbox value type if needed
7627 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7628 *target = mono_object_unbox (obj);
7634 * mono_object_to_string:
7636 * @exc: Any exception thrown by ToString (). May be NULL.
7638 * Returns: the result of calling ToString () on an object.
7641 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7644 MonoString *s = NULL;
7646 MonoMethod *method = prepare_to_string_method (obj, &target);
7648 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7649 if (*exc == NULL && !mono_error_ok (&error))
7650 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7652 mono_error_cleanup (&error);
7654 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7655 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7662 * mono_object_to_string_checked:
7664 * @error: Set on error.
7666 * Returns: the result of calling ToString () on an object. If the
7667 * method cannot be invoked or if it raises an exception, sets @error
7671 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7673 mono_error_init (error);
7675 MonoMethod *method = prepare_to_string_method (obj, &target);
7676 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7680 * mono_object_try_to_string:
7682 * @exc: Any exception thrown by ToString (). Must not be NULL.
7683 * @error: Set if method cannot be invoked.
7685 * Returns: the result of calling ToString () on an object. If the
7686 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7690 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7693 mono_error_init (error);
7695 MonoMethod *method = prepare_to_string_method (obj, &target);
7696 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7702 * mono_print_unhandled_exception:
7703 * @exc: The exception
7705 * Prints the unhandled exception.
7708 mono_print_unhandled_exception (MonoObject *exc)
7710 MONO_REQ_GC_UNSAFE_MODE;
7713 char *message = (char*)"";
7714 gboolean free_message = FALSE;
7717 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7718 message = g_strdup ("OutOfMemoryException");
7719 free_message = TRUE;
7720 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7721 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7722 free_message = TRUE;
7725 if (((MonoException*)exc)->native_trace_ips) {
7726 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7727 free_message = TRUE;
7729 MonoObject *other_exc = NULL;
7730 str = mono_object_try_to_string (exc, &other_exc, &error);
7731 if (other_exc == NULL && !is_ok (&error))
7732 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7734 mono_error_cleanup (&error);
7736 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7737 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7739 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7740 original_backtrace, nested_backtrace);
7742 g_free (original_backtrace);
7743 g_free (nested_backtrace);
7744 free_message = TRUE;
7746 message = mono_string_to_utf8_checked (str, &error);
7747 if (!mono_error_ok (&error)) {
7748 mono_error_cleanup (&error);
7749 message = (char *) "";
7751 free_message = TRUE;
7758 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7759 * exc->vtable->klass->name, message);
7761 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7768 * mono_delegate_ctor_with_method:
7769 * @this: pointer to an uninitialized delegate object
7770 * @target: target object
7771 * @addr: pointer to native code
7773 * @error: set on error.
7775 * Initialize a delegate and sets a specific method, not the one
7776 * associated with addr. This is useful when sharing generic code.
7777 * In that case addr will most probably not be associated with the
7778 * correct instantiation of the method.
7779 * On failure returns FALSE and sets @error.
7782 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7784 MONO_REQ_GC_UNSAFE_MODE;
7786 mono_error_init (error);
7787 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7789 g_assert (this_obj);
7792 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7795 delegate->method = method;
7797 mono_stats.delegate_creations++;
7799 #ifndef DISABLE_REMOTING
7800 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7802 method = mono_marshal_get_remoting_invoke (method);
7803 delegate->method_ptr = mono_compile_method_checked (method, error);
7804 return_val_if_nok (error, FALSE);
7805 MONO_OBJECT_SETREF (delegate, target, target);
7809 delegate->method_ptr = addr;
7810 MONO_OBJECT_SETREF (delegate, target, target);
7813 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7814 if (callbacks.init_delegate)
7815 callbacks.init_delegate (delegate);
7820 * mono_delegate_ctor:
7821 * @this: pointer to an uninitialized delegate object
7822 * @target: target object
7823 * @addr: pointer to native code
7824 * @error: set on error.
7826 * This is used to initialize a delegate.
7827 * On failure returns FALSE and sets @error.
7830 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7832 MONO_REQ_GC_UNSAFE_MODE;
7834 mono_error_init (error);
7835 MonoDomain *domain = mono_domain_get ();
7837 MonoMethod *method = NULL;
7841 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7843 if (!ji && domain != mono_get_root_domain ())
7844 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7846 method = mono_jit_info_get_method (ji);
7847 g_assert (!mono_class_is_gtd (method->klass));
7850 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7854 * mono_method_call_message_new:
7855 * @method: method to encapsulate
7856 * @params: parameters to the method
7857 * @invoke: optional, delegate invoke.
7858 * @cb: async callback delegate.
7859 * @state: state passed to the async callback.
7860 * @error: set on error.
7862 * Translates arguments pointers into a MonoMethodMessage.
7863 * On failure returns NULL and sets @error.
7866 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7867 MonoDelegate **cb, MonoObject **state, MonoError *error)
7869 MONO_REQ_GC_UNSAFE_MODE;
7871 mono_error_init (error);
7873 MonoDomain *domain = mono_domain_get ();
7874 MonoMethodSignature *sig = mono_method_signature (method);
7875 MonoMethodMessage *msg;
7878 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7879 return_val_if_nok (error, NULL);
7882 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7883 return_val_if_nok (error, NULL);
7884 mono_message_init (domain, msg, rm, NULL, error);
7885 return_val_if_nok (error, NULL);
7886 count = sig->param_count - 2;
7888 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7889 return_val_if_nok (error, NULL);
7890 mono_message_init (domain, msg, rm, NULL, error);
7891 return_val_if_nok (error, NULL);
7892 count = sig->param_count;
7895 for (i = 0; i < count; i++) {
7900 if (sig->params [i]->byref)
7901 vpos = *((gpointer *)params [i]);
7905 klass = mono_class_from_mono_type (sig->params [i]);
7907 if (klass->valuetype) {
7908 arg = mono_value_box_checked (domain, klass, vpos, error);
7909 return_val_if_nok (error, NULL);
7911 arg = *((MonoObject **)vpos);
7913 mono_array_setref (msg->args, i, arg);
7916 if (cb != NULL && state != NULL) {
7917 *cb = *((MonoDelegate **)params [i]);
7919 *state = *((MonoObject **)params [i]);
7926 * mono_method_return_message_restore:
7928 * Restore results from message based processing back to arguments pointers
7931 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7933 MONO_REQ_GC_UNSAFE_MODE;
7935 mono_error_init (error);
7937 MonoMethodSignature *sig = mono_method_signature (method);
7938 int i, j, type, size, out_len;
7940 if (out_args == NULL)
7942 out_len = mono_array_length (out_args);
7946 for (i = 0, j = 0; i < sig->param_count; i++) {
7947 MonoType *pt = sig->params [i];
7952 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7956 arg = (char *)mono_array_get (out_args, gpointer, j);
7959 g_assert (type != MONO_TYPE_VOID);
7961 if (MONO_TYPE_IS_REFERENCE (pt)) {
7962 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7965 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7966 size = mono_class_value_size (klass, NULL);
7967 if (klass->has_references)
7968 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7970 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7972 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7973 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7982 #ifndef DISABLE_REMOTING
7985 * mono_load_remote_field:
7986 * @this: pointer to an object
7987 * @klass: klass of the object containing @field
7988 * @field: the field to load
7989 * @res: a storage to store the result
7991 * This method is called by the runtime on attempts to load fields of
7992 * transparent proxy objects. @this points to such TP, @klass is the class of
7993 * the object containing @field. @res is a storage location which can be
7994 * used to store the result.
7996 * Returns: an address pointing to the value of field.
7999 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8002 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8003 mono_error_cleanup (&error);
8008 * mono_load_remote_field_checked:
8009 * @this: pointer to an object
8010 * @klass: klass of the object containing @field
8011 * @field: the field to load
8012 * @res: a storage to store the result
8013 * @error: set on error
8015 * This method is called by the runtime on attempts to load fields of
8016 * transparent proxy objects. @this points to such TP, @klass is the class of
8017 * the object containing @field. @res is a storage location which can be
8018 * used to store the result.
8020 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8023 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8025 MONO_REQ_GC_UNSAFE_MODE;
8027 static MonoMethod *getter = NULL;
8029 mono_error_init (error);
8031 MonoDomain *domain = mono_domain_get ();
8032 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8033 MonoClass *field_class;
8034 MonoMethodMessage *msg;
8035 MonoArray *out_args;
8039 g_assert (mono_object_is_transparent_proxy (this_obj));
8040 g_assert (res != NULL);
8042 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8043 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8048 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8050 mono_error_set_not_supported (error, "Linked away.");
8055 field_class = mono_class_from_mono_type (field->type);
8057 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8058 return_val_if_nok (error, NULL);
8059 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8060 return_val_if_nok (error, NULL);
8061 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8062 return_val_if_nok (error, NULL);
8063 mono_message_init (domain, msg, rm, out_args, error);
8064 return_val_if_nok (error, NULL);
8066 full_name = mono_type_get_full_name (klass);
8067 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8068 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8071 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8072 return_val_if_nok (error, NULL);
8075 mono_error_set_exception_instance (error, (MonoException *)exc);
8079 if (mono_array_length (out_args) == 0)
8082 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8084 if (field_class->valuetype) {
8085 return ((char *)*res) + sizeof (MonoObject);
8091 * mono_load_remote_field_new:
8096 * Missing documentation.
8099 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8103 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8104 mono_error_cleanup (&error);
8109 * mono_load_remote_field_new_checked:
8110 * @this: pointer to an object
8111 * @klass: klass of the object containing @field
8112 * @field: the field to load
8113 * @error: set on error.
8115 * This method is called by the runtime on attempts to load fields of
8116 * transparent proxy objects. @this points to such TP, @klass is the class of
8117 * the object containing @field.
8119 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8122 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8124 MONO_REQ_GC_UNSAFE_MODE;
8126 mono_error_init (error);
8128 static MonoMethod *tp_load = NULL;
8130 g_assert (mono_object_is_transparent_proxy (this_obj));
8133 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8135 mono_error_set_not_supported (error, "Linked away.");
8140 /* MonoType *type = mono_class_get_type (klass); */
8146 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8150 * mono_store_remote_field:
8151 * @this_obj: pointer to an object
8152 * @klass: klass of the object containing @field
8153 * @field: the field to load
8154 * @val: the value/object to store
8156 * This method is called by the runtime on attempts to store fields of
8157 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8158 * the object containing @field. @val is the new value to store in @field.
8161 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8164 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8165 mono_error_cleanup (&error);
8169 * mono_store_remote_field_checked:
8170 * @this_obj: pointer to an object
8171 * @klass: klass of the object containing @field
8172 * @field: the field to load
8173 * @val: the value/object to store
8174 * @error: set on error
8176 * This method is called by the runtime on attempts to store fields of
8177 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8178 * the object containing @field. @val is the new value to store in @field.
8180 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8183 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8186 MONO_REQ_GC_UNSAFE_MODE;
8188 mono_error_init (error);
8190 MonoDomain *domain = mono_domain_get ();
8191 MonoClass *field_class;
8194 g_assert (mono_object_is_transparent_proxy (this_obj));
8196 field_class = mono_class_from_mono_type (field->type);
8198 if (field_class->valuetype) {
8199 arg = mono_value_box_checked (domain, field_class, val, error);
8200 return_val_if_nok (error, FALSE);
8202 arg = *((MonoObject**)val);
8205 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8209 * mono_store_remote_field_new:
8215 * Missing documentation
8218 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8221 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8222 mono_error_cleanup (&error);
8226 * mono_store_remote_field_new_checked:
8233 * Missing documentation
8236 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8238 MONO_REQ_GC_UNSAFE_MODE;
8240 static MonoMethod *tp_store = NULL;
8242 mono_error_init (error);
8244 g_assert (mono_object_is_transparent_proxy (this_obj));
8247 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8249 mono_error_set_not_supported (error, "Linked away.");
8259 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8260 return is_ok (error);
8265 * mono_create_ftnptr:
8267 * Given a function address, create a function descriptor for it.
8268 * This is only needed on some platforms.
8271 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8273 return callbacks.create_ftnptr (domain, addr);
8277 * mono_get_addr_from_ftnptr:
8279 * Given a pointer to a function descriptor, return the function address.
8280 * This is only needed on some platforms.
8283 mono_get_addr_from_ftnptr (gpointer descr)
8285 return callbacks.get_addr_from_ftnptr (descr);
8289 * mono_string_chars:
8292 * Returns a pointer to the UCS16 characters stored in the MonoString
8295 mono_string_chars (MonoString *s)
8297 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8303 * mono_string_length:
8306 * Returns the lenght in characters of the string
8309 mono_string_length (MonoString *s)
8311 MONO_REQ_GC_UNSAFE_MODE;
8317 * mono_array_length:
8318 * @array: a MonoArray*
8320 * Returns the total number of elements in the array. This works for
8321 * both vectors and multidimensional arrays.
8324 mono_array_length (MonoArray *array)
8326 MONO_REQ_GC_UNSAFE_MODE;
8328 return array->max_length;
8332 * mono_array_addr_with_size:
8333 * @array: a MonoArray*
8334 * @size: size of the array elements
8335 * @idx: index into the array
8337 * Use this function to obtain the address for the @idx item on the
8338 * @array containing elements of size @size.
8340 * This method performs no bounds checking or type checking.
8342 * Returns the address of the @idx element in the array.
8345 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8347 MONO_REQ_GC_UNSAFE_MODE;
8349 return ((char*)(array)->vector) + size * idx;
8354 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8356 MonoDomain *domain = mono_domain_get ();
8360 mono_error_init (error);
8364 len = g_list_length (list);
8365 res = mono_array_new_checked (domain, eclass, len, error);
8366 return_val_if_nok (error, NULL);
8368 for (i = 0; list; list = list->next, i++)
8369 mono_array_set (res, gpointer, i, list->data);
8376 * The following section is purely to declare prototypes and
8377 * document the API, as these C files are processed by our
8383 * @array: array to alter
8384 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8385 * @index: index into the array
8386 * @value: value to set
8388 * Value Type version: This sets the @index's element of the @array
8389 * with elements of size sizeof(type) to the provided @value.
8391 * This macro does not attempt to perform type checking or bounds checking.
8393 * Use this to set value types in a `MonoArray`.
8395 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8400 * mono_array_setref:
8401 * @array: array to alter
8402 * @index: index into the array
8403 * @value: value to set
8405 * Reference Type version: This sets the @index's element of the
8406 * @array with elements of size sizeof(type) to the provided @value.
8408 * This macro does not attempt to perform type checking or bounds checking.
8410 * Use this to reference types in a `MonoArray`.
8412 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8418 * @array: array on which to operate on
8419 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8420 * @index: index into the array
8422 * Use this macro to retrieve the @index element of an @array and
8423 * extract the value assuming that the elements of the array match
8424 * the provided type value.
8426 * This method can be used with both arrays holding value types and
8427 * reference types. For reference types, the @type parameter should
8428 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8430 * This macro does not attempt to perform type checking or bounds checking.
8432 * Returns: The element at the @index position in the @array.
8434 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)