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 && iface->is_inflated) {
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 (iface->generic_class->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;
1669 GenericVirtualCase *gvc, *list;
1670 MonoImtBuilderEntry *entries;
1674 mono_domain_lock (domain);
1675 if (!domain->generic_virtual_cases)
1676 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1678 /* Check whether the case was already added */
1679 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1682 if (gvc->method == method)
1687 /* If not found, make a new one */
1689 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1690 gvc->method = method;
1693 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1695 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1698 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1704 if (++gvc->count == THUNK_THRESHOLD) {
1705 gpointer vtable_trampoline = NULL;
1706 gpointer imt_trampoline = NULL;
1708 if ((gpointer)vtable_slot < (gpointer)vtable) {
1709 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1710 int imt_slot = MONO_IMT_SIZE + displacement;
1712 /* Force the rebuild of the trampoline at the next call */
1713 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1714 *vtable_slot = imt_trampoline;
1716 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1718 entries = get_generic_virtual_entries (domain, vtable_slot);
1720 sorted = imt_sort_slot_entries (entries);
1722 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1726 MonoImtBuilderEntry *next = entries->next;
1731 for (i = 0; i < sorted->len; ++i)
1732 g_free (g_ptr_array_index (sorted, i));
1733 g_ptr_array_free (sorted, TRUE);
1737 mono_domain_unlock (domain);
1740 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1743 * mono_class_vtable:
1744 * @domain: the application domain
1745 * @class: the class to initialize
1747 * VTables are domain specific because we create domain specific code, and
1748 * they contain the domain specific static class data.
1749 * On failure, NULL is returned, and class->exception_type is set.
1752 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1755 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1756 mono_error_cleanup (&error);
1761 * mono_class_vtable_full:
1762 * @domain: the application domain
1763 * @class: the class to initialize
1764 * @error set on failure.
1766 * VTables are domain specific because we create domain specific code, and
1767 * they contain the domain specific static class data.
1770 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1772 MONO_REQ_GC_UNSAFE_MODE;
1774 MonoClassRuntimeInfo *runtime_info;
1776 mono_error_init (error);
1780 if (mono_class_has_failure (klass)) {
1781 mono_error_set_for_class_failure (error, klass);
1785 /* this check can be inlined in jitted code, too */
1786 runtime_info = klass->runtime_info;
1787 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1788 return runtime_info->domain_vtables [domain->domain_id];
1789 return mono_class_create_runtime_vtable (domain, klass, error);
1793 * mono_class_try_get_vtable:
1794 * @domain: the application domain
1795 * @class: the class to initialize
1797 * This function tries to get the associated vtable from @class if
1798 * it was already created.
1801 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1803 MONO_REQ_GC_NEUTRAL_MODE;
1805 MonoClassRuntimeInfo *runtime_info;
1809 runtime_info = klass->runtime_info;
1810 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1811 return runtime_info->domain_vtables [domain->domain_id];
1816 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1818 MONO_REQ_GC_NEUTRAL_MODE;
1820 size_t alloc_offset;
1823 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1824 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1825 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1827 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1828 g_assert ((imt_table_bytes & 7) == 4);
1835 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1839 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1841 MONO_REQ_GC_UNSAFE_MODE;
1844 MonoClassRuntimeInfo *runtime_info, *old_info;
1845 MonoClassField *field;
1847 int i, vtable_slots;
1848 size_t imt_table_bytes;
1850 guint32 vtable_size, class_size;
1852 gpointer *interface_offsets;
1854 mono_error_init (error);
1856 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1857 mono_domain_lock (domain);
1858 runtime_info = klass->runtime_info;
1859 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1860 mono_domain_unlock (domain);
1861 mono_loader_unlock ();
1862 return runtime_info->domain_vtables [domain->domain_id];
1864 if (!klass->inited || mono_class_has_failure (klass)) {
1865 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1866 mono_domain_unlock (domain);
1867 mono_loader_unlock ();
1868 mono_error_set_for_class_failure (error, klass);
1873 /* Array types require that their element type be valid*/
1874 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1875 MonoClass *element_class = klass->element_class;
1876 if (!element_class->inited)
1877 mono_class_init (element_class);
1879 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1880 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1881 mono_class_setup_vtable (element_class);
1883 if (mono_class_has_failure (element_class)) {
1884 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1885 if (!mono_class_has_failure (klass))
1886 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1887 mono_domain_unlock (domain);
1888 mono_loader_unlock ();
1889 mono_error_set_for_class_failure (error, klass);
1895 * For some classes, mono_class_init () already computed klass->vtable_size, and
1896 * that is all that is needed because of the vtable trampolines.
1898 if (!klass->vtable_size)
1899 mono_class_setup_vtable (klass);
1901 if (klass->generic_class && !klass->vtable)
1902 mono_class_check_vtable_constraints (klass, NULL);
1904 /* Initialize klass->has_finalize */
1905 mono_class_has_finalizer (klass);
1907 if (mono_class_has_failure (klass)) {
1908 mono_domain_unlock (domain);
1909 mono_loader_unlock ();
1910 mono_error_set_for_class_failure (error, klass);
1914 vtable_slots = klass->vtable_size;
1915 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1916 class_size = mono_class_data_size (klass);
1920 if (klass->interface_offsets_count) {
1921 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1922 mono_stats.imt_number_of_tables++;
1923 mono_stats.imt_tables_size += imt_table_bytes;
1925 imt_table_bytes = 0;
1928 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1930 mono_stats.used_class_count++;
1931 mono_stats.class_vtable_size += vtable_size;
1933 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1934 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1935 g_assert (!((gsize)vt & 7));
1938 vt->rank = klass->rank;
1939 vt->domain = domain;
1941 mono_class_compute_gc_descriptor (klass);
1943 * We can't use typed allocation in the non-root domains, since the
1944 * collector needs the GC descriptor stored in the vtable even after
1945 * the mempool containing the vtable is destroyed when the domain is
1946 * unloaded. An alternative might be to allocate vtables in the GC
1947 * heap, but this does not seem to work (it leads to crashes inside
1948 * libgc). If that approach is tried, two gc descriptors need to be
1949 * allocated for each class: one for the root domain, and one for all
1950 * other domains. The second descriptor should contain a bit for the
1951 * vtable field in MonoObject, since we can no longer assume the
1952 * vtable is reachable by other roots after the appdomain is unloaded.
1954 #ifdef HAVE_BOEHM_GC
1955 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1956 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1959 vt->gc_descr = klass->gc_descr;
1961 gc_bits = mono_gc_get_vtable_bits (klass);
1962 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1964 vt->gc_bits = gc_bits;
1967 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1968 if (klass->has_static_refs) {
1969 MonoGCDescriptor statics_gc_descr;
1971 gsize default_bitmap [4] = {0};
1974 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1975 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1976 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1977 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1978 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1979 if (bitmap != default_bitmap)
1982 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1984 vt->has_static_fields = TRUE;
1985 mono_stats.class_static_data_size += class_size;
1989 while ((field = mono_class_get_fields (klass, &iter))) {
1990 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1992 if (mono_field_is_deleted (field))
1994 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1995 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1996 if (special_static != SPECIAL_STATIC_NONE) {
1997 guint32 size, offset;
1999 gsize default_bitmap [4] = {0};
2004 if (mono_type_is_reference (field->type)) {
2005 default_bitmap [0] = 1;
2007 bitmap = default_bitmap;
2008 } else if (mono_type_is_struct (field->type)) {
2009 fclass = mono_class_from_mono_type (field->type);
2010 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2011 numbits = max_set + 1;
2013 default_bitmap [0] = 0;
2015 bitmap = default_bitmap;
2017 size = mono_type_size (field->type, &align);
2018 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2019 if (!domain->special_static_fields)
2020 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2021 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2022 if (bitmap != default_bitmap)
2025 * This marks the field as special static to speed up the
2026 * checks in mono_field_static_get/set_value ().
2032 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2033 MonoClass *fklass = mono_class_from_mono_type (field->type);
2034 const char *data = mono_field_get_data (field);
2036 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2037 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2038 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2041 if (fklass->valuetype) {
2042 memcpy (t, data, mono_class_value_size (fklass, NULL));
2044 /* it's a pointer type: add check */
2045 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2052 vt->max_interface_id = klass->max_interface_id;
2053 vt->interface_bitmap = klass->interface_bitmap;
2055 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2056 // class->name, klass->interface_offsets_count);
2058 /* Initialize vtable */
2059 if (callbacks.get_vtable_trampoline) {
2060 // This also covers the AOT case
2061 for (i = 0; i < klass->vtable_size; ++i) {
2062 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2065 mono_class_setup_vtable (klass);
2067 for (i = 0; i < klass->vtable_size; ++i) {
2070 cm = klass->vtable [i];
2072 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2073 if (!is_ok (error)) {
2074 mono_domain_unlock (domain);
2075 mono_loader_unlock ();
2082 if (imt_table_bytes) {
2083 /* Now that the vtable is full, we can actually fill up the IMT */
2084 for (i = 0; i < MONO_IMT_SIZE; ++i)
2085 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2089 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2090 * re-acquire them and check if another thread has created the vtable in the meantime.
2092 /* Special case System.MonoType to avoid infinite recursion */
2093 if (klass != mono_defaults.runtimetype_class) {
2094 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2095 if (!is_ok (error)) {
2096 mono_domain_unlock (domain);
2097 mono_loader_unlock ();
2101 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2102 /* This is unregistered in
2103 unregister_vtable_reflection_type() in
2105 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2108 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2110 /* class_vtable_array keeps an array of created vtables
2112 g_ptr_array_add (domain->class_vtable_array, vt);
2113 /* klass->runtime_info is protected by the loader lock, both when
2114 * it it enlarged and when it is stored info.
2118 * Store the vtable in klass->runtime_info.
2119 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2121 mono_memory_barrier ();
2123 old_info = klass->runtime_info;
2124 if (old_info && old_info->max_domain >= domain->domain_id) {
2125 /* someone already created a large enough runtime info */
2126 old_info->domain_vtables [domain->domain_id] = vt;
2128 int new_size = domain->domain_id;
2130 new_size = MAX (new_size, old_info->max_domain);
2132 /* make the new size a power of two */
2134 while (new_size > i)
2137 /* this is a bounded memory retention issue: may want to
2138 * handle it differently when we'll have a rcu-like system.
2140 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2141 runtime_info->max_domain = new_size - 1;
2142 /* copy the stuff from the older info */
2144 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2146 runtime_info->domain_vtables [domain->domain_id] = vt;
2148 mono_memory_barrier ();
2149 klass->runtime_info = runtime_info;
2152 if (klass == mono_defaults.runtimetype_class) {
2153 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2154 if (!is_ok (error)) {
2155 mono_domain_unlock (domain);
2156 mono_loader_unlock ();
2160 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2161 /* This is unregistered in
2162 unregister_vtable_reflection_type() in
2164 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2167 mono_domain_unlock (domain);
2168 mono_loader_unlock ();
2170 /* make sure the parent is initialized */
2171 /*FIXME shouldn't this fail the current type?*/
2173 mono_class_vtable_full (domain, klass->parent, error);
2178 #ifndef DISABLE_REMOTING
2180 * mono_class_proxy_vtable:
2181 * @domain: the application domain
2182 * @remove_class: the remote class
2183 * @error: set on error
2185 * Creates a vtable for transparent proxies. It is basically
2186 * a copy of the real vtable of the class wrapped in @remote_class,
2187 * but all function pointers invoke the remoting functions, and
2188 * vtable->klass points to the transparent proxy class, and not to @class.
2190 * On failure returns NULL and sets @error
2193 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2195 MONO_REQ_GC_UNSAFE_MODE;
2197 MonoVTable *vt, *pvt;
2198 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2200 GSList *extra_interfaces = NULL;
2201 MonoClass *klass = remote_class->proxy_class;
2202 gpointer *interface_offsets;
2203 uint8_t *bitmap = NULL;
2205 size_t imt_table_bytes;
2207 #ifdef COMPRESSED_INTERFACE_BITMAP
2211 mono_error_init (error);
2213 vt = mono_class_vtable (domain, klass);
2214 g_assert (vt); /*FIXME property handle failure*/
2215 max_interface_id = vt->max_interface_id;
2217 /* Calculate vtable space for extra interfaces */
2218 for (j = 0; j < remote_class->interface_count; j++) {
2219 MonoClass* iclass = remote_class->interfaces[j];
2223 /*FIXME test for interfaces with variant generic arguments*/
2224 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2225 continue; /* interface implemented by the class */
2226 if (g_slist_find (extra_interfaces, iclass))
2229 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2231 method_count = mono_class_num_methods (iclass);
2233 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2237 for (i = 0; i < ifaces->len; ++i) {
2238 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2239 /*FIXME test for interfaces with variant generic arguments*/
2240 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2241 continue; /* interface implemented by the class */
2242 if (g_slist_find (extra_interfaces, ic))
2244 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2245 method_count += mono_class_num_methods (ic);
2247 g_ptr_array_free (ifaces, TRUE);
2251 extra_interface_vtsize += method_count * sizeof (gpointer);
2252 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2255 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2256 mono_stats.imt_number_of_tables++;
2257 mono_stats.imt_tables_size += imt_table_bytes;
2259 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2261 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2263 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2264 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2265 g_assert (!((gsize)pvt & 7));
2267 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2269 pvt->klass = mono_defaults.transparent_proxy_class;
2270 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2271 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2273 /* initialize vtable */
2274 mono_class_setup_vtable (klass);
2275 for (i = 0; i < klass->vtable_size; ++i) {
2278 if ((cm = klass->vtable [i])) {
2279 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2283 pvt->vtable [i] = NULL;
2286 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2287 /* create trampolines for abstract methods */
2288 for (k = klass; k; k = k->parent) {
2290 gpointer iter = NULL;
2291 while ((m = mono_class_get_methods (k, &iter)))
2292 if (!pvt->vtable [m->slot]) {
2293 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2300 pvt->max_interface_id = max_interface_id;
2301 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2302 #ifdef COMPRESSED_INTERFACE_BITMAP
2303 bitmap = (uint8_t *)g_malloc0 (bsize);
2305 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2308 for (i = 0; i < klass->interface_offsets_count; ++i) {
2309 int interface_id = klass->interfaces_packed [i]->interface_id;
2310 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2313 if (extra_interfaces) {
2314 int slot = klass->vtable_size;
2320 /* Create trampolines for the methods of the interfaces */
2321 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2322 interf = (MonoClass *)list_item->data;
2324 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2328 while ((cm = mono_class_get_methods (interf, &iter))) {
2329 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2334 slot += mono_class_num_methods (interf);
2338 /* Now that the vtable is full, we can actually fill up the IMT */
2339 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2340 if (extra_interfaces) {
2341 g_slist_free (extra_interfaces);
2344 #ifdef COMPRESSED_INTERFACE_BITMAP
2345 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2346 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2347 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2350 pvt->interface_bitmap = bitmap;
2354 if (extra_interfaces)
2355 g_slist_free (extra_interfaces);
2356 #ifdef COMPRESSED_INTERFACE_BITMAP
2362 #endif /* DISABLE_REMOTING */
2365 * mono_class_field_is_special_static:
2367 * Returns whether @field is a thread/context static field.
2370 mono_class_field_is_special_static (MonoClassField *field)
2372 MONO_REQ_GC_NEUTRAL_MODE
2374 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2376 if (mono_field_is_deleted (field))
2378 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2379 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2386 * mono_class_field_get_special_static_type:
2387 * @field: The MonoClassField describing the field.
2389 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2390 * SPECIAL_STATIC_NONE otherwise.
2393 mono_class_field_get_special_static_type (MonoClassField *field)
2395 MONO_REQ_GC_NEUTRAL_MODE
2397 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2398 return SPECIAL_STATIC_NONE;
2399 if (mono_field_is_deleted (field))
2400 return SPECIAL_STATIC_NONE;
2401 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2402 return field_is_special_static (field->parent, field);
2403 return SPECIAL_STATIC_NONE;
2407 * mono_class_has_special_static_fields:
2409 * Returns whenever @klass has any thread/context static fields.
2412 mono_class_has_special_static_fields (MonoClass *klass)
2414 MONO_REQ_GC_NEUTRAL_MODE
2416 MonoClassField *field;
2420 while ((field = mono_class_get_fields (klass, &iter))) {
2421 g_assert (field->parent == klass);
2422 if (mono_class_field_is_special_static (field))
2429 #ifndef DISABLE_REMOTING
2431 * create_remote_class_key:
2432 * Creates an array of pointers that can be used as a hash key for a remote class.
2433 * The first element of the array is the number of pointers.
2436 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2438 MONO_REQ_GC_NEUTRAL_MODE;
2443 if (remote_class == NULL) {
2444 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2445 key = (void **)g_malloc (sizeof(gpointer) * 3);
2446 key [0] = GINT_TO_POINTER (2);
2447 key [1] = mono_defaults.marshalbyrefobject_class;
2448 key [2] = extra_class;
2450 key = (void **)g_malloc (sizeof(gpointer) * 2);
2451 key [0] = GINT_TO_POINTER (1);
2452 key [1] = extra_class;
2455 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2456 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2457 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2458 key [1] = remote_class->proxy_class;
2460 // Keep the list of interfaces sorted
2461 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2462 if (extra_class && remote_class->interfaces [i] > extra_class) {
2463 key [j++] = extra_class;
2466 key [j] = remote_class->interfaces [i];
2469 key [j] = extra_class;
2471 // Replace the old class. The interface list is the same
2472 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2473 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2474 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2475 for (i = 0; i < remote_class->interface_count; i++)
2476 key [2 + i] = remote_class->interfaces [i];
2484 * copy_remote_class_key:
2486 * Make a copy of KEY in the domain and return the copy.
2489 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2491 MONO_REQ_GC_NEUTRAL_MODE
2493 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2494 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2496 memcpy (mp_key, key, key_size);
2502 * mono_remote_class:
2503 * @domain: the application domain
2504 * @class_name: name of the remote class
2505 * @error: set on error
2507 * Creates and initializes a MonoRemoteClass object for a remote type.
2509 * On failure returns NULL and sets @error
2512 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2514 MONO_REQ_GC_UNSAFE_MODE;
2516 MonoRemoteClass *rc;
2517 gpointer* key, *mp_key;
2520 mono_error_init (error);
2522 key = create_remote_class_key (NULL, proxy_class);
2524 mono_domain_lock (domain);
2525 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2529 mono_domain_unlock (domain);
2533 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2534 if (!is_ok (error)) {
2536 mono_domain_unlock (domain);
2540 mp_key = copy_remote_class_key (domain, key);
2544 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2545 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2546 rc->interface_count = 1;
2547 rc->interfaces [0] = proxy_class;
2548 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2550 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2551 rc->interface_count = 0;
2552 rc->proxy_class = proxy_class;
2555 rc->default_vtable = NULL;
2556 rc->xdomain_vtable = NULL;
2557 rc->proxy_class_name = name;
2558 #ifndef DISABLE_PERFCOUNTERS
2559 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2562 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2564 mono_domain_unlock (domain);
2569 * clone_remote_class:
2570 * Creates a copy of the remote_class, adding the provided class or interface
2572 static MonoRemoteClass*
2573 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2575 MONO_REQ_GC_NEUTRAL_MODE;
2577 MonoRemoteClass *rc;
2578 gpointer* key, *mp_key;
2580 key = create_remote_class_key (remote_class, extra_class);
2581 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2587 mp_key = copy_remote_class_key (domain, key);
2591 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2593 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2594 rc->proxy_class = remote_class->proxy_class;
2595 rc->interface_count = remote_class->interface_count + 1;
2597 // Keep the list of interfaces sorted, since the hash key of
2598 // the remote class depends on this
2599 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2600 if (remote_class->interfaces [i] > extra_class && i == j)
2601 rc->interfaces [j++] = extra_class;
2602 rc->interfaces [j] = remote_class->interfaces [i];
2605 rc->interfaces [j] = extra_class;
2607 // Replace the old class. The interface array is the same
2608 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2609 rc->proxy_class = extra_class;
2610 rc->interface_count = remote_class->interface_count;
2611 if (rc->interface_count > 0)
2612 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2615 rc->default_vtable = NULL;
2616 rc->xdomain_vtable = NULL;
2617 rc->proxy_class_name = remote_class->proxy_class_name;
2619 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2625 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2627 MONO_REQ_GC_UNSAFE_MODE;
2629 mono_error_init (error);
2631 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2632 mono_domain_lock (domain);
2633 if (rp->target_domain_id != -1) {
2634 if (remote_class->xdomain_vtable == NULL)
2635 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2636 mono_domain_unlock (domain);
2637 mono_loader_unlock ();
2638 return_val_if_nok (error, NULL);
2639 return remote_class->xdomain_vtable;
2641 if (remote_class->default_vtable == NULL) {
2644 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2645 klass = mono_class_from_mono_type (type);
2647 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)))
2648 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2651 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2652 /* N.B. both branches of the if modify error */
2653 if (!is_ok (error)) {
2654 mono_domain_unlock (domain);
2655 mono_loader_unlock ();
2660 mono_domain_unlock (domain);
2661 mono_loader_unlock ();
2662 return remote_class->default_vtable;
2666 * mono_upgrade_remote_class:
2667 * @domain: the application domain
2668 * @tproxy: the proxy whose remote class has to be upgraded.
2669 * @klass: class to which the remote class can be casted.
2670 * @error: set on error
2672 * Updates the vtable of the remote class by adding the necessary method slots
2673 * and interface offsets so it can be safely casted to klass. klass can be a
2674 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2677 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2679 MONO_REQ_GC_UNSAFE_MODE;
2681 MonoTransparentProxy *tproxy;
2682 MonoRemoteClass *remote_class;
2683 gboolean redo_vtable;
2685 mono_error_init (error);
2686 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2687 mono_domain_lock (domain);
2689 tproxy = (MonoTransparentProxy*) proxy_object;
2690 remote_class = tproxy->remote_class;
2692 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2695 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2696 if (remote_class->interfaces [i] == klass)
2697 redo_vtable = FALSE;
2700 redo_vtable = (remote_class->proxy_class != klass);
2704 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2705 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2711 mono_domain_unlock (domain);
2712 mono_loader_unlock ();
2713 return is_ok (error);
2715 #endif /* DISABLE_REMOTING */
2719 * mono_object_get_virtual_method:
2720 * @obj: object to operate on.
2723 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2724 * the instance of a callvirt of method.
2727 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2729 MONO_REQ_GC_UNSAFE_MODE;
2732 MonoMethod **vtable;
2733 gboolean is_proxy = FALSE;
2734 MonoMethod *res = NULL;
2736 klass = mono_object_class (obj);
2737 #ifndef DISABLE_REMOTING
2738 if (klass == mono_defaults.transparent_proxy_class) {
2739 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2744 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2747 mono_class_setup_vtable (klass);
2748 vtable = klass->vtable;
2750 if (method->slot == -1) {
2751 /* method->slot might not be set for instances of generic methods */
2752 if (method->is_inflated) {
2753 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2754 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2757 g_assert_not_reached ();
2761 /* check method->slot is a valid index: perform isinstance? */
2762 if (method->slot != -1) {
2763 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2765 gboolean variance_used = FALSE;
2766 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2767 g_assert (iface_offset > 0);
2768 res = vtable [iface_offset + method->slot];
2771 res = vtable [method->slot];
2775 #ifndef DISABLE_REMOTING
2777 /* It may be an interface, abstract class method or generic method */
2778 if (!res || mono_method_signature (res)->generic_param_count)
2781 /* generic methods demand invoke_with_check */
2782 if (mono_method_signature (res)->generic_param_count)
2783 res = mono_marshal_get_remoting_invoke_with_check (res);
2786 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2787 res = mono_cominterop_get_invoke (res);
2790 res = mono_marshal_get_remoting_invoke (res);
2795 if (method->is_inflated) {
2797 /* Have to inflate the result */
2798 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2799 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2809 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2811 MONO_REQ_GC_UNSAFE_MODE;
2813 MonoObject *result = NULL;
2815 g_assert (callbacks.runtime_invoke);
2817 mono_error_init (error);
2819 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2820 mono_profiler_method_start_invoke (method);
2822 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2824 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2825 mono_profiler_method_end_invoke (method);
2827 if (!mono_error_ok (error))
2834 * mono_runtime_invoke:
2835 * @method: method to invoke
2836 * @obJ: object instance
2837 * @params: arguments to the method
2838 * @exc: exception information.
2840 * Invokes the method represented by @method on the object @obj.
2842 * obj is the 'this' pointer, it should be NULL for static
2843 * methods, a MonoObject* for object instances and a pointer to
2844 * the value type for value types.
2846 * The params array contains the arguments to the method with the
2847 * same convention: MonoObject* pointers for object instances and
2848 * pointers to the value type otherwise.
2850 * From unmanaged code you'll usually use the
2851 * mono_runtime_invoke() variant.
2853 * Note that this function doesn't handle virtual methods for
2854 * you, it will exec the exact method you pass: we still need to
2855 * expose a function to lookup the derived class implementation
2856 * of a virtual method (there are examples of this in the code,
2859 * You can pass NULL as the exc argument if you don't want to
2860 * catch exceptions, otherwise, *exc will be set to the exception
2861 * thrown, if any. if an exception is thrown, you can't use the
2862 * MonoObject* result from the function.
2864 * If the method returns a value type, it is boxed in an object
2868 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2873 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2874 if (*exc == NULL && !mono_error_ok(&error)) {
2875 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2877 mono_error_cleanup (&error);
2879 res = mono_runtime_invoke_checked (method, obj, params, &error);
2880 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2886 * mono_runtime_try_invoke:
2887 * @method: method to invoke
2888 * @obJ: object instance
2889 * @params: arguments to the method
2890 * @exc: exception information.
2891 * @error: set on error
2893 * Invokes the method represented by @method on the object @obj.
2895 * obj is the 'this' pointer, it should be NULL for static
2896 * methods, a MonoObject* for object instances and a pointer to
2897 * the value type for value types.
2899 * The params array contains the arguments to the method with the
2900 * same convention: MonoObject* pointers for object instances and
2901 * pointers to the value type otherwise.
2903 * From unmanaged code you'll usually use the
2904 * mono_runtime_invoke() variant.
2906 * Note that this function doesn't handle virtual methods for
2907 * you, it will exec the exact method you pass: we still need to
2908 * expose a function to lookup the derived class implementation
2909 * of a virtual method (there are examples of this in the code,
2912 * For this function, you must not pass NULL as the exc argument if
2913 * you don't want to catch exceptions, use
2914 * mono_runtime_invoke_checked(). If an exception is thrown, you
2915 * can't use the MonoObject* result from the function.
2917 * If this method cannot be invoked, @error will be set and @exc and
2918 * the return value must not be used.
2920 * If the method returns a value type, it is boxed in an object
2924 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2926 MONO_REQ_GC_UNSAFE_MODE;
2928 g_assert (exc != NULL);
2930 if (mono_runtime_get_no_exec ())
2931 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2933 return do_runtime_invoke (method, obj, params, exc, error);
2937 * mono_runtime_invoke_checked:
2938 * @method: method to invoke
2939 * @obJ: object instance
2940 * @params: arguments to the method
2941 * @error: set on error
2943 * Invokes the method represented by @method on the object @obj.
2945 * obj is the 'this' pointer, it should be NULL for static
2946 * methods, a MonoObject* for object instances and a pointer to
2947 * the value type for value types.
2949 * The params array contains the arguments to the method with the
2950 * same convention: MonoObject* pointers for object instances and
2951 * pointers to the value type otherwise.
2953 * From unmanaged code you'll usually use the
2954 * mono_runtime_invoke() variant.
2956 * Note that this function doesn't handle virtual methods for
2957 * you, it will exec the exact method you pass: we still need to
2958 * expose a function to lookup the derived class implementation
2959 * of a virtual method (there are examples of this in the code,
2962 * If an exception is thrown, you can't use the MonoObject* result
2963 * from the function.
2965 * If this method cannot be invoked, @error will be set. If the
2966 * method throws an exception (and we're in coop mode) the exception
2967 * will be set in @error.
2969 * If the method returns a value type, it is boxed in an object
2973 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2975 MONO_REQ_GC_UNSAFE_MODE;
2977 if (mono_runtime_get_no_exec ())
2978 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2980 return do_runtime_invoke (method, obj, params, NULL, error);
2984 * mono_method_get_unmanaged_thunk:
2985 * @method: method to generate a thunk for.
2987 * Returns an unmanaged->managed thunk that can be used to call
2988 * a managed method directly from C.
2990 * The thunk's C signature closely matches the managed signature:
2992 * C#: public bool Equals (object obj);
2993 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2994 * MonoObject*, MonoException**);
2996 * The 1st ("this") parameter must not be used with static methods:
2998 * C#: public static bool ReferenceEquals (object a, object b);
2999 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3002 * The last argument must be a non-null pointer of a MonoException* pointer.
3003 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3004 * exception has been thrown in managed code. Otherwise it will point
3005 * to the MonoException* caught by the thunk. In this case, the result of
3006 * the thunk is undefined:
3008 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3009 * MonoException *ex = NULL;
3010 * Equals func = mono_method_get_unmanaged_thunk (method);
3011 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3013 * // handle exception
3016 * The calling convention of the thunk matches the platform's default
3017 * convention. This means that under Windows, C declarations must
3018 * contain the __stdcall attribute:
3020 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3021 * MonoObject*, MonoException**);
3025 * Value type arguments and return values are treated as they were objects:
3027 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3028 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3030 * Arguments must be properly boxed upon trunk's invocation, while return
3031 * values must be unboxed.
3034 mono_method_get_unmanaged_thunk (MonoMethod *method)
3036 MONO_REQ_GC_NEUTRAL_MODE;
3037 MONO_REQ_API_ENTRYPOINT;
3042 g_assert (!mono_threads_is_coop_enabled ());
3044 MONO_ENTER_GC_UNSAFE;
3045 method = mono_marshal_get_thunk_invoke_wrapper (method);
3046 res = mono_compile_method_checked (method, &error);
3047 mono_error_cleanup (&error);
3048 MONO_EXIT_GC_UNSAFE;
3054 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3056 MONO_REQ_GC_UNSAFE_MODE;
3060 /* object fields cannot be byref, so we don't need a
3062 gpointer *p = (gpointer*)dest;
3069 case MONO_TYPE_BOOLEAN:
3071 case MONO_TYPE_U1: {
3072 guint8 *p = (guint8*)dest;
3073 *p = value ? *(guint8*)value : 0;
3078 case MONO_TYPE_CHAR: {
3079 guint16 *p = (guint16*)dest;
3080 *p = value ? *(guint16*)value : 0;
3083 #if SIZEOF_VOID_P == 4
3088 case MONO_TYPE_U4: {
3089 gint32 *p = (gint32*)dest;
3090 *p = value ? *(gint32*)value : 0;
3093 #if SIZEOF_VOID_P == 8
3098 case MONO_TYPE_U8: {
3099 gint64 *p = (gint64*)dest;
3100 *p = value ? *(gint64*)value : 0;
3103 case MONO_TYPE_R4: {
3104 float *p = (float*)dest;
3105 *p = value ? *(float*)value : 0;
3108 case MONO_TYPE_R8: {
3109 double *p = (double*)dest;
3110 *p = value ? *(double*)value : 0;
3113 case MONO_TYPE_STRING:
3114 case MONO_TYPE_SZARRAY:
3115 case MONO_TYPE_CLASS:
3116 case MONO_TYPE_OBJECT:
3117 case MONO_TYPE_ARRAY:
3118 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3120 case MONO_TYPE_FNPTR:
3121 case MONO_TYPE_PTR: {
3122 gpointer *p = (gpointer*)dest;
3123 *p = deref_pointer? *(gpointer*)value: value;
3126 case MONO_TYPE_VALUETYPE:
3127 /* note that 't' and 'type->type' can be different */
3128 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3129 t = mono_class_enum_basetype (type->data.klass)->type;
3132 MonoClass *klass = mono_class_from_mono_type (type);
3133 int size = mono_class_value_size (klass, NULL);
3135 mono_gc_bzero_atomic (dest, size);
3137 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3140 case MONO_TYPE_GENERICINST:
3141 t = type->data.generic_class->container_class->byval_arg.type;
3144 g_error ("got type %x", type->type);
3149 * mono_field_set_value:
3150 * @obj: Instance object
3151 * @field: MonoClassField describing the field to set
3152 * @value: The value to be set
3154 * Sets the value of the field described by @field in the object instance @obj
3155 * to the value passed in @value. This method should only be used for instance
3156 * fields. For static fields, use mono_field_static_set_value.
3158 * The value must be on the native format of the field type.
3161 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3163 MONO_REQ_GC_UNSAFE_MODE;
3167 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3169 dest = (char*)obj + field->offset;
3170 mono_copy_value (field->type, dest, value, FALSE);
3174 * mono_field_static_set_value:
3175 * @field: MonoClassField describing the field to set
3176 * @value: The value to be set
3178 * Sets the value of the static field described by @field
3179 * to the value passed in @value.
3181 * The value must be on the native format of the field type.
3184 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3186 MONO_REQ_GC_UNSAFE_MODE;
3190 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3191 /* you cant set a constant! */
3192 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3194 if (field->offset == -1) {
3195 /* Special static */
3198 mono_domain_lock (vt->domain);
3199 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3200 mono_domain_unlock (vt->domain);
3201 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3203 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3205 mono_copy_value (field->type, dest, value, FALSE);
3209 * mono_vtable_get_static_field_data:
3211 * Internal use function: return a pointer to the memory holding the static fields
3212 * for a class or NULL if there are no static fields.
3213 * This is exported only for use by the debugger.
3216 mono_vtable_get_static_field_data (MonoVTable *vt)
3218 MONO_REQ_GC_NEUTRAL_MODE
3220 if (!vt->has_static_fields)
3222 return vt->vtable [vt->klass->vtable_size];
3226 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3228 MONO_REQ_GC_UNSAFE_MODE;
3232 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3233 if (field->offset == -1) {
3234 /* Special static */
3237 mono_domain_lock (vt->domain);
3238 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3239 mono_domain_unlock (vt->domain);
3240 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3242 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3245 src = (guint8*)obj + field->offset;
3252 * mono_field_get_value:
3253 * @obj: Object instance
3254 * @field: MonoClassField describing the field to fetch information from
3255 * @value: pointer to the location where the value will be stored
3257 * Use this routine to get the value of the field @field in the object
3260 * The pointer provided by value must be of the field type, for reference
3261 * types this is a MonoObject*, for value types its the actual pointer to
3266 * mono_field_get_value (obj, int_field, &i);
3269 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3271 MONO_REQ_GC_UNSAFE_MODE;
3277 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3279 src = (char*)obj + field->offset;
3280 mono_copy_value (field->type, value, src, TRUE);
3284 * mono_field_get_value_object:
3285 * @domain: domain where the object will be created (if boxing)
3286 * @field: MonoClassField describing the field to fetch information from
3287 * @obj: The object instance for the field.
3289 * Returns: a new MonoObject with the value from the given field. If the
3290 * field represents a value type, the value is boxed.
3294 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3297 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3298 mono_error_assert_ok (&error);
3303 * mono_field_get_value_object_checked:
3304 * @domain: domain where the object will be created (if boxing)
3305 * @field: MonoClassField describing the field to fetch information from
3306 * @obj: The object instance for the field.
3307 * @error: Set on error.
3309 * Returns: a new MonoObject with the value from the given field. If the
3310 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3314 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3316 MONO_REQ_GC_UNSAFE_MODE;
3318 mono_error_init (error);
3322 MonoVTable *vtable = NULL;
3324 gboolean is_static = FALSE;
3325 gboolean is_ref = FALSE;
3326 gboolean is_literal = FALSE;
3327 gboolean is_ptr = FALSE;
3328 MonoType *type = mono_field_get_type_checked (field, error);
3330 return_val_if_nok (error, NULL);
3332 switch (type->type) {
3333 case MONO_TYPE_STRING:
3334 case MONO_TYPE_OBJECT:
3335 case MONO_TYPE_CLASS:
3336 case MONO_TYPE_ARRAY:
3337 case MONO_TYPE_SZARRAY:
3342 case MONO_TYPE_BOOLEAN:
3345 case MONO_TYPE_CHAR:
3354 case MONO_TYPE_VALUETYPE:
3355 is_ref = type->byref;
3357 case MONO_TYPE_GENERICINST:
3358 is_ref = !mono_type_generic_inst_is_valuetype (type);
3364 g_error ("type 0x%x not handled in "
3365 "mono_field_get_value_object", type->type);
3369 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3372 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3376 vtable = mono_class_vtable_full (domain, field->parent, error);
3377 return_val_if_nok (error, NULL);
3379 if (!vtable->initialized) {
3380 mono_runtime_class_init_full (vtable, error);
3381 return_val_if_nok (error, NULL);
3390 get_default_field_value (domain, field, &o, error);
3391 return_val_if_nok (error, NULL);
3392 } else if (is_static) {
3393 mono_field_static_get_value_checked (vtable, field, &o, error);
3394 return_val_if_nok (error, NULL);
3396 mono_field_get_value (obj, field, &o);
3402 static MonoMethod *m;
3408 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3409 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3415 get_default_field_value (domain, field, v, error);
3416 return_val_if_nok (error, NULL);
3417 } else if (is_static) {
3418 mono_field_static_get_value_checked (vtable, field, v, error);
3419 return_val_if_nok (error, NULL);
3421 mono_field_get_value (obj, field, v);
3424 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3425 args [0] = ptr ? *ptr : NULL;
3426 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3427 return_val_if_nok (error, NULL);
3429 o = mono_runtime_invoke_checked (m, NULL, args, error);
3430 return_val_if_nok (error, NULL);
3435 /* boxed value type */
3436 klass = mono_class_from_mono_type (type);
3438 if (mono_class_is_nullable (klass))
3439 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3441 o = mono_object_new_checked (domain, klass, error);
3442 return_val_if_nok (error, NULL);
3443 v = ((gchar *) o) + sizeof (MonoObject);
3446 get_default_field_value (domain, field, v, error);
3447 return_val_if_nok (error, NULL);
3448 } else if (is_static) {
3449 mono_field_static_get_value_checked (vtable, field, v, error);
3450 return_val_if_nok (error, NULL);
3452 mono_field_get_value (obj, field, v);
3459 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3461 MONO_REQ_GC_UNSAFE_MODE;
3463 mono_error_init (error);
3465 const char *p = blob;
3466 mono_metadata_decode_blob_size (p, &p);
3469 case MONO_TYPE_BOOLEAN:
3472 *(guint8 *) value = *p;
3474 case MONO_TYPE_CHAR:
3477 *(guint16*) value = read16 (p);
3481 *(guint32*) value = read32 (p);
3485 *(guint64*) value = read64 (p);
3488 readr4 (p, (float*) value);
3491 readr8 (p, (double*) value);
3493 case MONO_TYPE_STRING:
3494 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3496 case MONO_TYPE_CLASS:
3497 *(gpointer*) value = NULL;
3501 g_warning ("type 0x%02x should not be in constant table", type);
3507 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3509 MONO_REQ_GC_NEUTRAL_MODE;
3511 MonoTypeEnum def_type;
3514 mono_error_init (error);
3516 data = mono_class_get_field_default_value (field, &def_type);
3517 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3521 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3523 MONO_REQ_GC_UNSAFE_MODE;
3527 mono_error_init (error);
3529 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3531 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3532 get_default_field_value (vt->domain, field, value, error);
3536 if (field->offset == -1) {
3537 /* Special static */
3538 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3539 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3541 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3543 mono_copy_value (field->type, value, src, TRUE);
3547 * mono_field_static_get_value:
3548 * @vt: vtable to the object
3549 * @field: MonoClassField describing the field to fetch information from
3550 * @value: where the value is returned
3552 * Use this routine to get the value of the static field @field value.
3554 * The pointer provided by value must be of the field type, for reference
3555 * types this is a MonoObject*, for value types its the actual pointer to
3560 * mono_field_static_get_value (vt, int_field, &i);
3563 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3565 MONO_REQ_GC_NEUTRAL_MODE;
3568 mono_field_static_get_value_checked (vt, field, value, &error);
3569 mono_error_cleanup (&error);
3573 * mono_field_static_get_value_checked:
3574 * @vt: vtable to the object
3575 * @field: MonoClassField describing the field to fetch information from
3576 * @value: where the value is returned
3577 * @error: set on error
3579 * Use this routine to get the value of the static field @field value.
3581 * The pointer provided by value must be of the field type, for reference
3582 * types this is a MonoObject*, for value types its the actual pointer to
3587 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3588 * if (!is_ok (error)) { ... }
3590 * On failure sets @error.
3593 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3595 MONO_REQ_GC_NEUTRAL_MODE;
3597 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3601 * mono_property_set_value:
3602 * @prop: MonoProperty to set
3603 * @obj: instance object on which to act
3604 * @params: parameters to pass to the propery
3605 * @exc: optional exception
3607 * Invokes the property's set method with the given arguments on the
3608 * object instance obj (or NULL for static properties).
3610 * You can pass NULL as the exc argument if you don't want to
3611 * catch exceptions, otherwise, *exc will be set to the exception
3612 * thrown, if any. if an exception is thrown, you can't use the
3613 * MonoObject* result from the function.
3616 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3618 MONO_REQ_GC_UNSAFE_MODE;
3621 do_runtime_invoke (prop->set, obj, params, exc, &error);
3622 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3623 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3625 mono_error_cleanup (&error);
3630 * mono_property_set_value_checked:
3631 * @prop: MonoProperty to set
3632 * @obj: instance object on which to act
3633 * @params: parameters to pass to the propery
3634 * @error: set on error
3636 * Invokes the property's set method with the given arguments on the
3637 * object instance obj (or NULL for static properties).
3639 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3640 * If an exception is thrown, it will be caught and returned via @error.
3643 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3645 MONO_REQ_GC_UNSAFE_MODE;
3649 mono_error_init (error);
3650 do_runtime_invoke (prop->set, obj, params, &exc, error);
3651 if (exc != NULL && is_ok (error))
3652 mono_error_set_exception_instance (error, (MonoException*)exc);
3653 return is_ok (error);
3657 * mono_property_get_value:
3658 * @prop: MonoProperty to fetch
3659 * @obj: instance object on which to act
3660 * @params: parameters to pass to the propery
3661 * @exc: optional exception
3663 * Invokes the property's get method with the given arguments on the
3664 * object instance obj (or NULL for static properties).
3666 * You can pass NULL as the exc argument if you don't want to
3667 * catch exceptions, otherwise, *exc will be set to the exception
3668 * thrown, if any. if an exception is thrown, you can't use the
3669 * MonoObject* result from the function.
3671 * Returns: the value from invoking the get method on the property.
3674 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3676 MONO_REQ_GC_UNSAFE_MODE;
3679 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3680 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3681 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3683 mono_error_cleanup (&error); /* FIXME don't raise here */
3690 * mono_property_get_value_checked:
3691 * @prop: MonoProperty to fetch
3692 * @obj: instance object on which to act
3693 * @params: parameters to pass to the propery
3694 * @error: set on error
3696 * Invokes the property's get method with the given arguments on the
3697 * object instance obj (or NULL for static properties).
3699 * If an exception is thrown, you can't use the
3700 * MonoObject* result from the function. The exception will be propagated via @error.
3702 * Returns: the value from invoking the get method on the property. On
3703 * failure returns NULL and sets @error.
3706 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3708 MONO_REQ_GC_UNSAFE_MODE;
3711 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3712 if (exc != NULL && !is_ok (error))
3713 mono_error_set_exception_instance (error, (MonoException*) exc);
3721 * mono_nullable_init:
3722 * @buf: The nullable structure to initialize.
3723 * @value: the value to initialize from
3724 * @klass: the type for the object
3726 * Initialize the nullable structure pointed to by @buf from @value which
3727 * should be a boxed value type. The size of @buf should be able to hold
3728 * as much data as the @klass->instance_size (which is the number of bytes
3729 * that will be copies).
3731 * Since Nullables have variable structure, we can not define a C
3732 * structure for them.
3735 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3737 MONO_REQ_GC_UNSAFE_MODE;
3739 MonoClass *param_class = klass->cast_class;
3741 mono_class_setup_fields_locking (klass);
3742 g_assert (klass->fields_inited);
3744 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3745 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3747 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3749 if (param_class->has_references)
3750 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3752 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3754 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3759 * mono_nullable_box:
3760 * @buf: The buffer representing the data to be boxed
3761 * @klass: the type to box it as.
3762 * @error: set on oerr
3764 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3765 * @buf. On failure returns NULL and sets @error
3768 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3770 MONO_REQ_GC_UNSAFE_MODE;
3772 mono_error_init (error);
3773 MonoClass *param_class = klass->cast_class;
3775 mono_class_setup_fields_locking (klass);
3776 g_assert (klass->fields_inited);
3778 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3779 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3781 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3782 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3783 return_val_if_nok (error, NULL);
3784 if (param_class->has_references)
3785 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3787 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3795 * mono_get_delegate_invoke:
3796 * @klass: The delegate class
3798 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3801 mono_get_delegate_invoke (MonoClass *klass)
3803 MONO_REQ_GC_NEUTRAL_MODE;
3807 /* This is called at runtime, so avoid the slower search in metadata */
3808 mono_class_setup_methods (klass);
3809 if (mono_class_has_failure (klass))
3811 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3816 * mono_get_delegate_begin_invoke:
3817 * @klass: The delegate class
3819 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3822 mono_get_delegate_begin_invoke (MonoClass *klass)
3824 MONO_REQ_GC_NEUTRAL_MODE;
3828 /* This is called at runtime, so avoid the slower search in metadata */
3829 mono_class_setup_methods (klass);
3830 if (mono_class_has_failure (klass))
3832 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3837 * mono_get_delegate_end_invoke:
3838 * @klass: The delegate class
3840 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3843 mono_get_delegate_end_invoke (MonoClass *klass)
3845 MONO_REQ_GC_NEUTRAL_MODE;
3849 /* This is called at runtime, so avoid the slower search in metadata */
3850 mono_class_setup_methods (klass);
3851 if (mono_class_has_failure (klass))
3853 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3858 * mono_runtime_delegate_invoke:
3859 * @delegate: pointer to a delegate object.
3860 * @params: parameters for the delegate.
3861 * @exc: Pointer to the exception result.
3863 * Invokes the delegate method @delegate with the parameters provided.
3865 * You can pass NULL as the exc argument if you don't want to
3866 * catch exceptions, otherwise, *exc will be set to the exception
3867 * thrown, if any. if an exception is thrown, you can't use the
3868 * MonoObject* result from the function.
3871 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3873 MONO_REQ_GC_UNSAFE_MODE;
3877 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3879 mono_error_cleanup (&error);
3882 if (!is_ok (&error))
3883 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3887 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3888 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3894 * mono_runtime_delegate_try_invoke:
3895 * @delegate: pointer to a delegate object.
3896 * @params: parameters for the delegate.
3897 * @exc: Pointer to the exception result.
3898 * @error: set on error
3900 * Invokes the delegate method @delegate with the parameters provided.
3902 * You can pass NULL as the exc argument if you don't want to
3903 * catch exceptions, otherwise, *exc will be set to the exception
3904 * thrown, if any. On failure to execute, @error will be set.
3905 * if an exception is thrown, you can't use the
3906 * MonoObject* result from the function.
3909 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3911 MONO_REQ_GC_UNSAFE_MODE;
3913 mono_error_init (error);
3915 MonoClass *klass = delegate->vtable->klass;
3918 im = mono_get_delegate_invoke (klass);
3920 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3923 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3925 o = mono_runtime_invoke_checked (im, delegate, params, error);
3932 * mono_runtime_delegate_invoke_checked:
3933 * @delegate: pointer to a delegate object.
3934 * @params: parameters for the delegate.
3935 * @error: set on error
3937 * Invokes the delegate method @delegate with the parameters provided.
3939 * On failure @error will be set and you can't use the MonoObject*
3940 * result from the function.
3943 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3945 mono_error_init (error);
3946 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3949 static char **main_args = NULL;
3950 static int num_main_args = 0;
3953 * mono_runtime_get_main_args:
3955 * Returns: a MonoArray with the arguments passed to the main program
3958 mono_runtime_get_main_args (void)
3960 MONO_REQ_GC_UNSAFE_MODE;
3962 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3963 mono_error_assert_ok (&error);
3968 * mono_runtime_get_main_args:
3969 * @error: set on error
3971 * Returns: a MonoArray with the arguments passed to the main
3972 * program. On failure returns NULL and sets @error.
3975 mono_runtime_get_main_args_checked (MonoError *error)
3979 MonoDomain *domain = mono_domain_get ();
3981 mono_error_init (error);
3983 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3984 return_val_if_nok (error, NULL);
3986 for (i = 0; i < num_main_args; ++i)
3987 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3993 free_main_args (void)
3995 MONO_REQ_GC_NEUTRAL_MODE;
3999 for (i = 0; i < num_main_args; ++i)
4000 g_free (main_args [i]);
4007 * mono_runtime_set_main_args:
4008 * @argc: number of arguments from the command line
4009 * @argv: array of strings from the command line
4011 * Set the command line arguments from an embedding application that doesn't otherwise call
4012 * mono_runtime_run_main ().
4015 mono_runtime_set_main_args (int argc, char* argv[])
4017 MONO_REQ_GC_NEUTRAL_MODE;
4022 main_args = g_new0 (char*, argc);
4023 num_main_args = argc;
4025 for (i = 0; i < argc; ++i) {
4028 utf8_arg = mono_utf8_from_external (argv[i]);
4029 if (utf8_arg == NULL) {
4030 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4031 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4035 main_args [i] = utf8_arg;
4042 * Prepare an array of arguments in order to execute a standard Main()
4043 * method (argc/argv contains the executable name). This method also
4044 * sets the command line argument value needed by System.Environment.
4048 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4050 MONO_REQ_GC_UNSAFE_MODE;
4054 MonoArray *args = NULL;
4055 MonoDomain *domain = mono_domain_get ();
4056 gchar *utf8_fullpath;
4057 MonoMethodSignature *sig;
4059 g_assert (method != NULL);
4061 mono_thread_set_main (mono_thread_current ());
4063 main_args = g_new0 (char*, argc);
4064 num_main_args = argc;
4066 if (!g_path_is_absolute (argv [0])) {
4067 gchar *basename = g_path_get_basename (argv [0]);
4068 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4072 utf8_fullpath = mono_utf8_from_external (fullpath);
4073 if(utf8_fullpath == NULL) {
4074 /* Printing the arg text will cause glib to
4075 * whinge about "Invalid UTF-8", but at least
4076 * its relevant, and shows the problem text
4079 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4080 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4087 utf8_fullpath = mono_utf8_from_external (argv[0]);
4088 if(utf8_fullpath == NULL) {
4089 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4090 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4095 main_args [0] = utf8_fullpath;
4097 for (i = 1; i < argc; ++i) {
4100 utf8_arg=mono_utf8_from_external (argv[i]);
4101 if(utf8_arg==NULL) {
4102 /* Ditto the comment about Invalid UTF-8 here */
4103 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4104 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4108 main_args [i] = utf8_arg;
4113 sig = mono_method_signature (method);
4115 g_print ("Unable to load Main method.\n");
4119 if (sig->param_count) {
4120 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4121 mono_error_assert_ok (&error);
4122 for (i = 0; i < argc; ++i) {
4123 /* The encodings should all work, given that
4124 * we've checked all these args for the
4127 gchar *str = mono_utf8_from_external (argv [i]);
4128 MonoString *arg = mono_string_new (domain, str);
4129 mono_array_setref (args, i, arg);
4133 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4134 mono_error_assert_ok (&error);
4137 mono_assembly_set_main (method->klass->image->assembly);
4143 * mono_runtime_run_main:
4144 * @method: the method to start the application with (usually Main)
4145 * @argc: number of arguments from the command line
4146 * @argv: array of strings from the command line
4147 * @exc: excetption results
4149 * Execute a standard Main() method (argc/argv contains the
4150 * executable name). This method also sets the command line argument value
4151 * needed by System.Environment.
4156 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4159 MONO_REQ_GC_UNSAFE_MODE;
4162 MonoArray *args = prepare_run_main (method, argc, argv);
4165 res = mono_runtime_try_exec_main (method, args, exc);
4167 res = mono_runtime_exec_main_checked (method, args, &error);
4168 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4174 * mono_runtime_run_main_checked:
4175 * @method: the method to start the application with (usually Main)
4176 * @argc: number of arguments from the command line
4177 * @argv: array of strings from the command line
4178 * @error: set on error
4180 * Execute a standard Main() method (argc/argv contains the
4181 * executable name). This method also sets the command line argument value
4182 * needed by System.Environment. On failure sets @error.
4187 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4190 mono_error_init (error);
4191 MonoArray *args = prepare_run_main (method, argc, argv);
4192 return mono_runtime_exec_main_checked (method, args, error);
4196 * mono_runtime_try_run_main:
4197 * @method: the method to start the application with (usually Main)
4198 * @argc: number of arguments from the command line
4199 * @argv: array of strings from the command line
4200 * @exc: set if Main throws an exception
4201 * @error: set if Main can't be executed
4203 * Execute a standard Main() method (argc/argv contains the executable
4204 * name). This method also sets the command line argument value needed
4205 * by System.Environment. On failure sets @error if Main can't be
4206 * executed or @exc if it threw and exception.
4211 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4215 MonoArray *args = prepare_run_main (method, argc, argv);
4216 return mono_runtime_try_exec_main (method, args, exc);
4221 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4223 static MonoMethod *serialize_method;
4229 if (!serialize_method) {
4230 MonoClass *klass = mono_class_get_remoting_services_class ();
4231 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4234 if (!serialize_method) {
4239 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4244 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4245 if (*exc == NULL && !mono_error_ok (&error))
4246 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4248 mono_error_cleanup (&error);
4257 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4259 MONO_REQ_GC_UNSAFE_MODE;
4261 static MonoMethod *deserialize_method;
4267 if (!deserialize_method) {
4268 MonoClass *klass = mono_class_get_remoting_services_class ();
4269 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4271 if (!deserialize_method) {
4279 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4280 if (*exc == NULL && !mono_error_ok (&error))
4281 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4283 mono_error_cleanup (&error);
4291 #ifndef DISABLE_REMOTING
4293 make_transparent_proxy (MonoObject *obj, MonoError *error)
4295 MONO_REQ_GC_UNSAFE_MODE;
4297 static MonoMethod *get_proxy_method;
4299 MonoDomain *domain = mono_domain_get ();
4300 MonoRealProxy *real_proxy;
4301 MonoReflectionType *reflection_type;
4302 MonoTransparentProxy *transparent_proxy;
4304 mono_error_init (error);
4306 if (!get_proxy_method)
4307 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4309 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4311 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4312 return_val_if_nok (error, NULL);
4313 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4314 return_val_if_nok (error, NULL);
4316 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4317 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4319 MonoObject *exc = NULL;
4321 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4322 if (exc != NULL && is_ok (error))
4323 mono_error_set_exception_instance (error, (MonoException*)exc);
4325 return (MonoObject*) transparent_proxy;
4327 #endif /* DISABLE_REMOTING */
4330 * mono_object_xdomain_representation
4332 * @target_domain: a domain
4333 * @error: set on error.
4335 * Creates a representation of obj in the domain target_domain. This
4336 * is either a copy of obj arrived through via serialization and
4337 * deserialization or a proxy, depending on whether the object is
4338 * serializable or marshal by ref. obj must not be in target_domain.
4340 * If the object cannot be represented in target_domain, NULL is
4341 * returned and @error is set appropriately.
4344 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4346 MONO_REQ_GC_UNSAFE_MODE;
4348 mono_error_init (error);
4349 MonoObject *deserialized = NULL;
4351 #ifndef DISABLE_REMOTING
4352 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4353 deserialized = make_transparent_proxy (obj, error);
4358 gboolean failure = FALSE;
4359 MonoDomain *domain = mono_domain_get ();
4360 MonoObject *serialized;
4361 MonoObject *exc = NULL;
4363 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4364 serialized = serialize_object (obj, &failure, &exc);
4365 mono_domain_set_internal_with_options (target_domain, FALSE);
4367 deserialized = deserialize_object (serialized, &failure, &exc);
4368 if (domain != target_domain)
4369 mono_domain_set_internal_with_options (domain, FALSE);
4371 mono_error_set_exception_instance (error, (MonoException*)exc);
4374 return deserialized;
4377 /* Used in call_unhandled_exception_delegate */
4379 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4381 MONO_REQ_GC_UNSAFE_MODE;
4383 mono_error_init (error);
4386 MonoMethod *method = NULL;
4387 MonoBoolean is_terminating = TRUE;
4390 klass = mono_class_get_unhandled_exception_event_args_class ();
4391 mono_class_init (klass);
4393 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4394 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4398 args [1] = &is_terminating;
4400 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4401 return_val_if_nok (error, NULL);
4403 mono_runtime_invoke_checked (method, obj, args, error);
4404 return_val_if_nok (error, NULL);
4409 /* Used in mono_unhandled_exception */
4411 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4412 MONO_REQ_GC_UNSAFE_MODE;
4415 MonoObject *e = NULL;
4417 MonoDomain *current_domain = mono_domain_get ();
4419 if (domain != current_domain)
4420 mono_domain_set_internal_with_options (domain, FALSE);
4422 g_assert (domain == mono_object_domain (domain->domain));
4424 if (mono_object_domain (exc) != domain) {
4426 exc = mono_object_xdomain_representation (exc, domain, &error);
4428 if (!is_ok (&error)) {
4429 MonoError inner_error;
4430 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4431 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4432 mono_error_assert_ok (&inner_error);
4434 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4435 "System.Runtime.Serialization", "SerializationException",
4436 "Could not serialize unhandled exception.");
4440 g_assert (mono_object_domain (exc) == domain);
4442 pa [0] = domain->domain;
4443 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4444 mono_error_assert_ok (&error);
4445 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4446 if (!is_ok (&error)) {
4448 e = (MonoObject*)mono_error_convert_to_exception (&error);
4450 mono_error_cleanup (&error);
4453 if (domain != current_domain)
4454 mono_domain_set_internal_with_options (current_domain, FALSE);
4457 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4458 if (!mono_error_ok (&error)) {
4459 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4460 mono_error_cleanup (&error);
4462 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4468 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4471 * mono_runtime_unhandled_exception_policy_set:
4472 * @policy: the new policy
4474 * This is a VM internal routine.
4476 * Sets the runtime policy for handling unhandled exceptions.
4479 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4480 runtime_unhandled_exception_policy = policy;
4484 * mono_runtime_unhandled_exception_policy_get:
4486 * This is a VM internal routine.
4488 * Gets the runtime policy for handling unhandled exceptions.
4490 MonoRuntimeUnhandledExceptionPolicy
4491 mono_runtime_unhandled_exception_policy_get (void) {
4492 return runtime_unhandled_exception_policy;
4496 * mono_unhandled_exception:
4497 * @exc: exception thrown
4499 * This is a VM internal routine.
4501 * We call this function when we detect an unhandled exception
4502 * in the default domain.
4504 * It invokes the * UnhandledException event in AppDomain or prints
4505 * a warning to the console
4508 mono_unhandled_exception (MonoObject *exc)
4510 MONO_REQ_GC_UNSAFE_MODE;
4513 MonoClassField *field;
4514 MonoDomain *current_domain, *root_domain;
4515 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4517 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4520 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4523 current_domain = mono_domain_get ();
4524 root_domain = mono_get_root_domain ();
4526 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4527 mono_error_assert_ok (&error);
4528 if (current_domain != root_domain) {
4529 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4530 mono_error_assert_ok (&error);
4533 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4534 mono_print_unhandled_exception (exc);
4536 /* unhandled exception callbacks must not be aborted */
4537 mono_threads_begin_abort_protected_block ();
4538 if (root_appdomain_delegate)
4539 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4540 if (current_appdomain_delegate)
4541 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4542 mono_threads_end_abort_protected_block ();
4545 /* set exitcode only if we will abort the process */
4546 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4547 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4549 mono_environment_exitcode_set (1);
4554 * mono_runtime_exec_managed_code:
4555 * @domain: Application domain
4556 * @main_func: function to invoke from the execution thread
4557 * @main_args: parameter to the main_func
4559 * Launch a new thread to execute a function
4561 * main_func is called back from the thread with main_args as the
4562 * parameter. The callback function is expected to start Main()
4563 * eventually. This function then waits for all managed threads to
4565 * It is not necesseray anymore to execute managed code in a subthread,
4566 * so this function should not be used anymore by default: just
4567 * execute the code and then call mono_thread_manage ().
4570 mono_runtime_exec_managed_code (MonoDomain *domain,
4571 MonoMainThreadFunc main_func,
4575 mono_thread_create_checked (domain, main_func, main_args, &error);
4576 mono_error_assert_ok (&error);
4578 mono_thread_manage ();
4582 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4584 MonoInternalThread* thread = mono_thread_internal_current ();
4585 MonoCustomAttrInfo* cinfo;
4586 gboolean has_stathread_attribute;
4588 if (!domain->entry_assembly) {
4590 MonoAssembly *assembly;
4592 assembly = method->klass->image->assembly;
4593 domain->entry_assembly = assembly;
4594 /* Domains created from another domain already have application_base and configuration_file set */
4595 if (domain->setup->application_base == NULL) {
4596 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4599 if (domain->setup->configuration_file == NULL) {
4600 str = g_strconcat (assembly->image->name, ".config", NULL);
4601 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4603 mono_domain_set_options_from_config (domain);
4607 MonoError cattr_error;
4608 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4609 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4611 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4613 mono_custom_attrs_free (cinfo);
4615 has_stathread_attribute = FALSE;
4617 if (has_stathread_attribute) {
4618 thread->apartment_state = ThreadApartmentState_STA;
4620 thread->apartment_state = ThreadApartmentState_MTA;
4622 mono_thread_init_apartment_state ();
4627 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4629 MONO_REQ_GC_UNSAFE_MODE;
4634 mono_error_init (error);
4639 /* FIXME: check signature of method */
4640 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4642 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4644 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4647 mono_environment_exitcode_set (rval);
4649 mono_runtime_invoke_checked (method, NULL, pa, error);
4661 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4663 MONO_REQ_GC_UNSAFE_MODE;
4673 /* FIXME: check signature of method */
4674 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4675 MonoError inner_error;
4677 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4678 if (*exc == NULL && !mono_error_ok (&inner_error))
4679 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4681 mono_error_cleanup (&inner_error);
4684 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4688 mono_environment_exitcode_set (rval);
4690 MonoError inner_error;
4691 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4692 if (*exc == NULL && !mono_error_ok (&inner_error))
4693 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4695 mono_error_cleanup (&inner_error);
4700 /* If the return type of Main is void, only
4701 * set the exitcode if an exception was thrown
4702 * (we don't want to blow away an
4703 * explicitly-set exit code)
4706 mono_environment_exitcode_set (rval);
4714 * Execute a standard Main() method (args doesn't contain the
4718 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4721 prepare_thread_to_exec_main (mono_object_domain (args), method);
4723 int rval = do_try_exec_main (method, args, exc);
4726 int rval = do_exec_main_checked (method, args, &error);
4727 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4733 * Execute a standard Main() method (args doesn't contain the
4736 * On failure sets @error
4739 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4741 mono_error_init (error);
4742 prepare_thread_to_exec_main (mono_object_domain (args), method);
4743 return do_exec_main_checked (method, args, error);
4747 * Execute a standard Main() method (args doesn't contain the
4750 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4753 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4755 prepare_thread_to_exec_main (mono_object_domain (args), method);
4756 return do_try_exec_main (method, args, exc);
4761 /** invoke_array_extract_argument:
4762 * @params: array of arguments to the method.
4763 * @i: the index of the argument to extract.
4764 * @t: ith type from the method signature.
4765 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4766 * @error: set on error.
4768 * Given an array of method arguments, return the ith one using the corresponding type
4769 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4771 * On failure sets @error and returns NULL.
4774 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4776 MonoType *t_orig = t;
4777 gpointer result = NULL;
4778 mono_error_init (error);
4783 case MONO_TYPE_BOOLEAN:
4786 case MONO_TYPE_CHAR:
4795 case MONO_TYPE_VALUETYPE:
4796 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4797 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4798 result = mono_array_get (params, MonoObject*, i);
4800 *has_byref_nullables = TRUE;
4802 /* MS seems to create the objects if a null is passed in */
4803 if (!mono_array_get (params, MonoObject*, i)) {
4804 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4805 return_val_if_nok (error, NULL);
4806 mono_array_setref (params, i, o);
4811 * We can't pass the unboxed vtype byref to the callee, since
4812 * that would mean the callee would be able to modify boxed
4813 * primitive types. So we (and MS) make a copy of the boxed
4814 * object, pass that to the callee, and replace the original
4815 * boxed object in the arg array with the copy.
4817 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4818 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4819 return_val_if_nok (error, NULL);
4820 mono_array_setref (params, i, copy);
4823 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4826 case MONO_TYPE_STRING:
4827 case MONO_TYPE_OBJECT:
4828 case MONO_TYPE_CLASS:
4829 case MONO_TYPE_ARRAY:
4830 case MONO_TYPE_SZARRAY:
4832 result = mono_array_addr (params, MonoObject*, i);
4833 // FIXME: I need to check this code path
4835 result = mono_array_get (params, MonoObject*, i);
4837 case MONO_TYPE_GENERICINST:
4839 t = &t->data.generic_class->container_class->this_arg;
4841 t = &t->data.generic_class->container_class->byval_arg;
4843 case MONO_TYPE_PTR: {
4846 /* The argument should be an IntPtr */
4847 arg = mono_array_get (params, MonoObject*, i);
4851 g_assert (arg->vtable->klass == mono_defaults.int_class);
4852 result = ((MonoIntPtr*)arg)->m_value;
4857 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4862 * mono_runtime_invoke_array:
4863 * @method: method to invoke
4864 * @obJ: object instance
4865 * @params: arguments to the method
4866 * @exc: exception information.
4868 * Invokes the method represented by @method on the object @obj.
4870 * obj is the 'this' pointer, it should be NULL for static
4871 * methods, a MonoObject* for object instances and a pointer to
4872 * the value type for value types.
4874 * The params array contains the arguments to the method with the
4875 * same convention: MonoObject* pointers for object instances and
4876 * pointers to the value type otherwise. The _invoke_array
4877 * variant takes a C# object[] as the params argument (MonoArray
4878 * *params): in this case the value types are boxed inside the
4879 * respective reference representation.
4881 * From unmanaged code you'll usually use the
4882 * mono_runtime_invoke_checked() variant.
4884 * Note that this function doesn't handle virtual methods for
4885 * you, it will exec the exact method you pass: we still need to
4886 * expose a function to lookup the derived class implementation
4887 * of a virtual method (there are examples of this in the code,
4890 * You can pass NULL as the exc argument if you don't want to
4891 * catch exceptions, otherwise, *exc will be set to the exception
4892 * thrown, if any. if an exception is thrown, you can't use the
4893 * MonoObject* result from the function.
4895 * If the method returns a value type, it is boxed in an object
4899 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4904 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4906 mono_error_cleanup (&error);
4909 if (!is_ok (&error))
4910 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4914 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4915 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4921 * mono_runtime_invoke_array_checked:
4922 * @method: method to invoke
4923 * @obJ: object instance
4924 * @params: arguments to the method
4925 * @error: set on failure.
4927 * Invokes the method represented by @method on the object @obj.
4929 * obj is the 'this' pointer, it should be NULL for static
4930 * methods, a MonoObject* for object instances and a pointer to
4931 * the value type for value types.
4933 * The params array contains the arguments to the method with the
4934 * same convention: MonoObject* pointers for object instances and
4935 * pointers to the value type otherwise. The _invoke_array
4936 * variant takes a C# object[] as the params argument (MonoArray
4937 * *params): in this case the value types are boxed inside the
4938 * respective reference representation.
4940 * From unmanaged code you'll usually use the
4941 * mono_runtime_invoke_checked() variant.
4943 * Note that this function doesn't handle virtual methods for
4944 * you, it will exec the exact method you pass: we still need to
4945 * expose a function to lookup the derived class implementation
4946 * of a virtual method (there are examples of this in the code,
4949 * On failure or exception, @error will be set. In that case, you
4950 * can't use the MonoObject* result from the function.
4952 * If the method returns a value type, it is boxed in an object
4956 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4959 mono_error_init (error);
4960 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4964 * mono_runtime_try_invoke_array:
4965 * @method: method to invoke
4966 * @obJ: object instance
4967 * @params: arguments to the method
4968 * @exc: exception information.
4969 * @error: set on failure.
4971 * Invokes the method represented by @method on the object @obj.
4973 * obj is the 'this' pointer, it should be NULL for static
4974 * methods, a MonoObject* for object instances and a pointer to
4975 * the value type for value types.
4977 * The params array contains the arguments to the method with the
4978 * same convention: MonoObject* pointers for object instances and
4979 * pointers to the value type otherwise. The _invoke_array
4980 * variant takes a C# object[] as the params argument (MonoArray
4981 * *params): in this case the value types are boxed inside the
4982 * respective reference representation.
4984 * From unmanaged code you'll usually use the
4985 * mono_runtime_invoke_checked() variant.
4987 * Note that this function doesn't handle virtual methods for
4988 * you, it will exec the exact method you pass: we still need to
4989 * expose a function to lookup the derived class implementation
4990 * of a virtual method (there are examples of this in the code,
4993 * You can pass NULL as the exc argument if you don't want to catch
4994 * exceptions, otherwise, *exc will be set to the exception thrown, if
4995 * any. On other failures, @error will be set. If an exception is
4996 * thrown or there's an error, you can't use the MonoObject* result
4997 * from the function.
4999 * If the method returns a value type, it is boxed in an object
5003 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5004 MonoObject **exc, MonoError *error)
5006 MONO_REQ_GC_UNSAFE_MODE;
5008 mono_error_init (error);
5010 MonoMethodSignature *sig = mono_method_signature (method);
5011 gpointer *pa = NULL;
5014 gboolean has_byref_nullables = FALSE;
5016 if (NULL != params) {
5017 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5018 for (i = 0; i < mono_array_length (params); i++) {
5019 MonoType *t = sig->params [i];
5020 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5021 return_val_if_nok (error, NULL);
5025 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5028 if (mono_class_is_nullable (method->klass)) {
5029 /* Need to create a boxed vtype instead */
5035 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5040 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5041 mono_error_assert_ok (error);
5042 g_assert (obj); /*maybe we should raise a TLE instead?*/
5043 #ifndef DISABLE_REMOTING
5044 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5045 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5048 if (method->klass->valuetype)
5049 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5052 } else if (method->klass->valuetype) {
5053 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5054 return_val_if_nok (error, NULL);
5058 mono_runtime_try_invoke (method, o, pa, exc, error);
5060 mono_runtime_invoke_checked (method, o, pa, error);
5063 return (MonoObject *)obj;
5065 if (mono_class_is_nullable (method->klass)) {
5066 MonoObject *nullable;
5068 /* Convert the unboxed vtype into a Nullable structure */
5069 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5070 return_val_if_nok (error, NULL);
5072 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5073 return_val_if_nok (error, NULL);
5074 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5075 obj = mono_object_unbox (nullable);
5078 /* obj must be already unboxed if needed */
5080 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5082 res = mono_runtime_invoke_checked (method, obj, pa, error);
5084 return_val_if_nok (error, NULL);
5086 if (sig->ret->type == MONO_TYPE_PTR) {
5087 MonoClass *pointer_class;
5088 static MonoMethod *box_method;
5090 MonoObject *box_exc;
5093 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5094 * convert it to a Pointer object.
5096 pointer_class = mono_class_get_pointer_class ();
5098 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5100 g_assert (res->vtable->klass == mono_defaults.int_class);
5101 box_args [0] = ((MonoIntPtr*)res)->m_value;
5102 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5103 return_val_if_nok (error, NULL);
5105 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5106 g_assert (box_exc == NULL);
5107 mono_error_assert_ok (error);
5110 if (has_byref_nullables) {
5112 * The runtime invoke wrapper already converted byref nullables back,
5113 * and stored them in pa, we just need to copy them back to the
5116 for (i = 0; i < mono_array_length (params); i++) {
5117 MonoType *t = sig->params [i];
5119 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5120 mono_array_setref (params, i, pa [i]);
5130 * @klass: the class of the object that we want to create
5132 * Returns: a newly created object whose definition is
5133 * looked up using @klass. This will not invoke any constructors,
5134 * so the consumer of this routine has to invoke any constructors on
5135 * its own to initialize the object.
5137 * It returns NULL on failure.
5140 mono_object_new (MonoDomain *domain, MonoClass *klass)
5142 MONO_REQ_GC_UNSAFE_MODE;
5146 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5148 mono_error_cleanup (&error);
5153 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5155 MONO_REQ_GC_UNSAFE_MODE;
5159 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5161 mono_error_set_pending_exception (&error);
5166 * mono_object_new_checked:
5167 * @klass: the class of the object that we want to create
5168 * @error: set on error
5170 * Returns: a newly created object whose definition is
5171 * looked up using @klass. This will not invoke any constructors,
5172 * so the consumer of this routine has to invoke any constructors on
5173 * its own to initialize the object.
5175 * It returns NULL on failure and sets @error.
5178 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5180 MONO_REQ_GC_UNSAFE_MODE;
5184 vtable = mono_class_vtable (domain, klass);
5185 g_assert (vtable); /* FIXME don't swallow the error */
5187 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5192 * mono_object_new_pinned:
5194 * Same as mono_object_new, but the returned object will be pinned.
5195 * For SGEN, these objects will only be freed at appdomain unload.
5198 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5200 MONO_REQ_GC_UNSAFE_MODE;
5204 mono_error_init (error);
5206 vtable = mono_class_vtable (domain, klass);
5207 g_assert (vtable); /* FIXME don't swallow the error */
5209 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5211 if (G_UNLIKELY (!o))
5212 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5213 else if (G_UNLIKELY (vtable->klass->has_finalize))
5214 mono_object_register_finalizer (o);
5220 * mono_object_new_specific:
5221 * @vtable: the vtable of the object that we want to create
5223 * Returns: A newly created object with class and domain specified
5227 mono_object_new_specific (MonoVTable *vtable)
5230 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5231 mono_error_cleanup (&error);
5237 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5239 MONO_REQ_GC_UNSAFE_MODE;
5243 mono_error_init (error);
5245 /* check for is_com_object for COM Interop */
5246 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5249 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5252 MonoClass *klass = mono_class_get_activation_services_class ();
5255 mono_class_init (klass);
5257 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5259 mono_error_set_not_supported (error, "Linked away.");
5262 vtable->domain->create_proxy_for_type_method = im;
5265 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5266 if (!mono_error_ok (error))
5269 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5270 if (!mono_error_ok (error))
5277 return mono_object_new_alloc_specific_checked (vtable, error);
5281 ves_icall_object_new_specific (MonoVTable *vtable)
5284 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5285 mono_error_set_pending_exception (&error);
5291 * mono_object_new_alloc_specific:
5292 * @vtable: virtual table for the object.
5294 * This function allocates a new `MonoObject` with the type derived
5295 * from the @vtable information. If the class of this object has a
5296 * finalizer, then the object will be tracked for finalization.
5298 * This method might raise an exception on errors. Use the
5299 * `mono_object_new_fast_checked` method if you want to manually raise
5302 * Returns: the allocated object.
5305 mono_object_new_alloc_specific (MonoVTable *vtable)
5308 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5309 mono_error_cleanup (&error);
5315 * mono_object_new_alloc_specific_checked:
5316 * @vtable: virtual table for the object.
5317 * @error: holds the error return value.
5319 * This function allocates a new `MonoObject` with the type derived
5320 * from the @vtable information. If the class of this object has a
5321 * finalizer, then the object will be tracked for finalization.
5323 * If there is not enough memory, the @error parameter will be set
5324 * and will contain a user-visible message with the amount of bytes
5325 * that were requested.
5327 * Returns: the allocated object, or NULL if there is not enough memory
5331 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5333 MONO_REQ_GC_UNSAFE_MODE;
5337 mono_error_init (error);
5339 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5341 if (G_UNLIKELY (!o))
5342 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5343 else if (G_UNLIKELY (vtable->klass->has_finalize))
5344 mono_object_register_finalizer (o);
5350 * mono_object_new_fast:
5351 * @vtable: virtual table for the object.
5353 * This function allocates a new `MonoObject` with the type derived
5354 * from the @vtable information. The returned object is not tracked
5355 * for finalization. If your object implements a finalizer, you should
5356 * use `mono_object_new_alloc_specific` instead.
5358 * This method might raise an exception on errors. Use the
5359 * `mono_object_new_fast_checked` method if you want to manually raise
5362 * Returns: the allocated object.
5365 mono_object_new_fast (MonoVTable *vtable)
5368 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5369 mono_error_cleanup (&error);
5375 * mono_object_new_fast_checked:
5376 * @vtable: virtual table for the object.
5377 * @error: holds the error return value.
5379 * This function allocates a new `MonoObject` with the type derived
5380 * from the @vtable information. The returned object is not tracked
5381 * for finalization. If your object implements a finalizer, you should
5382 * use `mono_object_new_alloc_specific_checked` instead.
5384 * If there is not enough memory, the @error parameter will be set
5385 * and will contain a user-visible message with the amount of bytes
5386 * that were requested.
5388 * Returns: the allocated object, or NULL if there is not enough memory
5392 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5394 MONO_REQ_GC_UNSAFE_MODE;
5398 mono_error_init (error);
5400 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5402 if (G_UNLIKELY (!o))
5403 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5409 ves_icall_object_new_fast (MonoVTable *vtable)
5412 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5413 mono_error_set_pending_exception (&error);
5419 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5421 MONO_REQ_GC_UNSAFE_MODE;
5425 mono_error_init (error);
5427 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5429 if (G_UNLIKELY (!o))
5430 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5431 else if (G_UNLIKELY (vtable->klass->has_finalize))
5432 mono_object_register_finalizer (o);
5438 * mono_class_get_allocation_ftn:
5440 * @for_box: the object will be used for boxing
5441 * @pass_size_in_words:
5443 * Return the allocation function appropriate for the given class.
5447 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5449 MONO_REQ_GC_NEUTRAL_MODE;
5451 *pass_size_in_words = FALSE;
5453 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5454 return ves_icall_object_new_specific;
5456 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5458 return ves_icall_object_new_fast;
5461 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5462 * of the overhead of parameter passing.
5465 *pass_size_in_words = TRUE;
5466 #ifdef GC_REDIRECT_TO_LOCAL
5467 return GC_local_gcj_fast_malloc;
5469 return GC_gcj_fast_malloc;
5474 return ves_icall_object_new_specific;
5478 * mono_object_new_from_token:
5479 * @image: Context where the type_token is hosted
5480 * @token: a token of the type that we want to create
5482 * Returns: A newly created object whose definition is
5483 * looked up using @token in the @image image
5486 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5488 MONO_REQ_GC_UNSAFE_MODE;
5494 klass = mono_class_get_checked (image, token, &error);
5495 mono_error_assert_ok (&error);
5497 result = mono_object_new_checked (domain, klass, &error);
5499 mono_error_cleanup (&error);
5506 * mono_object_clone:
5507 * @obj: the object to clone
5509 * Returns: A newly created object who is a shallow copy of @obj
5512 mono_object_clone (MonoObject *obj)
5515 MonoObject *o = mono_object_clone_checked (obj, &error);
5516 mono_error_cleanup (&error);
5522 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5524 MONO_REQ_GC_UNSAFE_MODE;
5529 mono_error_init (error);
5531 size = obj->vtable->klass->instance_size;
5533 if (obj->vtable->klass->rank)
5534 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5536 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5538 if (G_UNLIKELY (!o)) {
5539 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5543 /* If the object doesn't contain references this will do a simple memmove. */
5544 mono_gc_wbarrier_object_copy (o, obj);
5546 if (obj->vtable->klass->has_finalize)
5547 mono_object_register_finalizer (o);
5552 * mono_array_full_copy:
5553 * @src: source array to copy
5554 * @dest: destination array
5556 * Copies the content of one array to another with exactly the same type and size.
5559 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5561 MONO_REQ_GC_UNSAFE_MODE;
5564 MonoClass *klass = src->obj.vtable->klass;
5566 g_assert (klass == dest->obj.vtable->klass);
5568 size = mono_array_length (src);
5569 g_assert (size == mono_array_length (dest));
5570 size *= mono_array_element_size (klass);
5572 if (klass->element_class->valuetype) {
5573 if (klass->element_class->has_references)
5574 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5576 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5578 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5581 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5586 * mono_array_clone_in_domain:
5587 * @domain: the domain in which the array will be cloned into
5588 * @array: the array to clone
5589 * @error: set on error
5591 * This routine returns a copy of the array that is hosted on the
5592 * specified MonoDomain. On failure returns NULL and sets @error.
5595 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5597 MONO_REQ_GC_UNSAFE_MODE;
5602 MonoClass *klass = array->obj.vtable->klass;
5604 mono_error_init (error);
5606 if (array->bounds == NULL) {
5607 size = mono_array_length (array);
5608 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5609 return_val_if_nok (error, NULL);
5611 size *= mono_array_element_size (klass);
5613 if (klass->element_class->valuetype) {
5614 if (klass->element_class->has_references)
5615 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5617 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5619 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5622 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5627 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5628 size = mono_array_element_size (klass);
5629 for (i = 0; i < klass->rank; ++i) {
5630 sizes [i] = array->bounds [i].length;
5631 size *= array->bounds [i].length;
5632 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5634 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5635 return_val_if_nok (error, NULL);
5637 if (klass->element_class->valuetype) {
5638 if (klass->element_class->has_references)
5639 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5641 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5643 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5646 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5654 * @array: the array to clone
5656 * Returns: A newly created array who is a shallow copy of @array
5659 mono_array_clone (MonoArray *array)
5661 MONO_REQ_GC_UNSAFE_MODE;
5664 MonoArray *result = mono_array_clone_checked (array, &error);
5665 mono_error_cleanup (&error);
5670 * mono_array_clone_checked:
5671 * @array: the array to clone
5672 * @error: set on error
5674 * Returns: A newly created array who is a shallow copy of @array. On
5675 * failure returns NULL and sets @error.
5678 mono_array_clone_checked (MonoArray *array, MonoError *error)
5681 MONO_REQ_GC_UNSAFE_MODE;
5682 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5685 /* helper macros to check for overflow when calculating the size of arrays */
5686 #ifdef MONO_BIG_ARRAYS
5687 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5688 #define MYGUINT_MAX MYGUINT64_MAX
5689 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5690 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5691 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5692 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5693 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5695 #define MYGUINT32_MAX 4294967295U
5696 #define MYGUINT_MAX MYGUINT32_MAX
5697 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5698 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5699 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5700 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5701 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5705 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5707 MONO_REQ_GC_NEUTRAL_MODE;
5711 byte_len = mono_array_element_size (klass);
5712 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5715 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5717 byte_len += MONO_SIZEOF_MONO_ARRAY;
5725 * mono_array_new_full:
5726 * @domain: domain where the object is created
5727 * @array_class: array class
5728 * @lengths: lengths for each dimension in the array
5729 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5731 * This routine creates a new array objects with the given dimensions,
5732 * lower bounds and type.
5735 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5738 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5739 mono_error_cleanup (&error);
5745 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5747 MONO_REQ_GC_UNSAFE_MODE;
5749 uintptr_t byte_len = 0, len, bounds_size;
5752 MonoArrayBounds *bounds;
5756 mono_error_init (error);
5758 if (!array_class->inited)
5759 mono_class_init (array_class);
5763 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5764 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5766 if (len > MONO_ARRAY_MAX_INDEX) {
5767 mono_error_set_generic_error (error, "System", "OverflowException", "");
5772 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5774 for (i = 0; i < array_class->rank; ++i) {
5775 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5776 mono_error_set_generic_error (error, "System", "OverflowException", "");
5779 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5780 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5787 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5788 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5794 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5795 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5798 byte_len = (byte_len + 3) & ~3;
5799 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5800 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5803 byte_len += bounds_size;
5806 * Following three lines almost taken from mono_object_new ():
5807 * they need to be kept in sync.
5809 vtable = mono_class_vtable_full (domain, array_class, error);
5810 return_val_if_nok (error, NULL);
5813 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5815 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5817 if (G_UNLIKELY (!o)) {
5818 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5822 array = (MonoArray*)o;
5824 bounds = array->bounds;
5827 for (i = 0; i < array_class->rank; ++i) {
5828 bounds [i].length = lengths [i];
5830 bounds [i].lower_bound = lower_bounds [i];
5839 * @domain: domain where the object is created
5840 * @eclass: element class
5841 * @n: number of array elements
5843 * This routine creates a new szarray with @n elements of type @eclass.
5846 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5848 MONO_REQ_GC_UNSAFE_MODE;
5851 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5852 mono_error_cleanup (&error);
5857 * mono_array_new_checked:
5858 * @domain: domain where the object is created
5859 * @eclass: element class
5860 * @n: number of array elements
5861 * @error: set on error
5863 * This routine creates a new szarray with @n elements of type @eclass.
5864 * On failure returns NULL and sets @error.
5867 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5871 mono_error_init (error);
5873 ac = mono_array_class_get (eclass, 1);
5876 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5877 return_val_if_nok (error, NULL);
5879 return mono_array_new_specific_checked (vtable, n, error);
5883 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5886 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5887 mono_error_set_pending_exception (&error);
5893 * mono_array_new_specific:
5894 * @vtable: a vtable in the appropriate domain for an initialized class
5895 * @n: number of array elements
5897 * This routine is a fast alternative to mono_array_new() for code which
5898 * can be sure about the domain it operates in.
5901 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5904 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5905 mono_error_cleanup (&error);
5911 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5913 MONO_REQ_GC_UNSAFE_MODE;
5918 mono_error_init (error);
5920 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5921 mono_error_set_generic_error (error, "System", "OverflowException", "");
5925 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5926 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5929 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5931 if (G_UNLIKELY (!o)) {
5932 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5936 return (MonoArray*)o;
5940 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5943 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5944 mono_error_set_pending_exception (&error);
5950 * mono_string_new_utf16:
5951 * @text: a pointer to an utf16 string
5952 * @len: the length of the string
5954 * Returns: A newly created string object which contains @text.
5957 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5959 MONO_REQ_GC_UNSAFE_MODE;
5962 MonoString *res = NULL;
5963 res = mono_string_new_utf16_checked (domain, text, len, &error);
5964 mono_error_cleanup (&error);
5970 * mono_string_new_utf16_checked:
5971 * @text: a pointer to an utf16 string
5972 * @len: the length of the string
5973 * @error: written on error.
5975 * Returns: A newly created string object which contains @text.
5976 * On error, returns NULL and sets @error.
5979 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5981 MONO_REQ_GC_UNSAFE_MODE;
5985 mono_error_init (error);
5987 s = mono_string_new_size_checked (domain, len, error);
5989 memcpy (mono_string_chars (s), text, len * 2);
5995 * mono_string_new_utf32:
5996 * @text: a pointer to an utf32 string
5997 * @len: the length of the string
5998 * @error: set on failure.
6000 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6003 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6005 MONO_REQ_GC_UNSAFE_MODE;
6008 mono_unichar2 *utf16_output = NULL;
6009 gint32 utf16_len = 0;
6010 GError *gerror = NULL;
6011 glong items_written;
6013 mono_error_init (error);
6014 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6017 g_error_free (gerror);
6019 while (utf16_output [utf16_len]) utf16_len++;
6021 s = mono_string_new_size_checked (domain, utf16_len, error);
6022 return_val_if_nok (error, NULL);
6024 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6026 g_free (utf16_output);
6032 * mono_string_new_utf32:
6033 * @text: a pointer to an utf32 string
6034 * @len: the length of the string
6036 * Returns: A newly created string object which contains @text.
6039 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6042 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6043 mono_error_cleanup (&error);
6048 * mono_string_new_size:
6049 * @text: a pointer to an utf16 string
6050 * @len: the length of the string
6052 * Returns: A newly created string object of @len
6055 mono_string_new_size (MonoDomain *domain, gint32 len)
6058 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6059 mono_error_cleanup (&error);
6065 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6067 MONO_REQ_GC_UNSAFE_MODE;
6073 mono_error_init (error);
6075 /* check for overflow */
6076 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6077 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6081 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6082 g_assert (size > 0);
6084 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6087 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6089 if (G_UNLIKELY (!s)) {
6090 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6098 * mono_string_new_len:
6099 * @text: a pointer to an utf8 string
6100 * @length: number of bytes in @text to consider
6102 * Returns: A newly created string object which contains @text.
6105 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6107 MONO_REQ_GC_UNSAFE_MODE;
6110 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6111 mono_error_cleanup (&error);
6116 * mono_string_new_len_checked:
6117 * @text: a pointer to an utf8 string
6118 * @length: number of bytes in @text to consider
6119 * @error: set on error
6121 * Returns: A newly created string object which contains @text. On
6122 * failure returns NULL and sets @error.
6125 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6127 MONO_REQ_GC_UNSAFE_MODE;
6129 mono_error_init (error);
6131 GError *eg_error = NULL;
6132 MonoString *o = NULL;
6134 glong items_written;
6136 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6139 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6141 g_error_free (eg_error);
6150 * @text: a pointer to an utf8 string
6152 * Returns: A newly created string object which contains @text.
6154 * This function asserts if it cannot allocate a new string.
6156 * @deprecated Use mono_string_new_checked in new code.
6159 mono_string_new (MonoDomain *domain, const char *text)
6162 MonoString *res = NULL;
6163 res = mono_string_new_checked (domain, text, &error);
6164 mono_error_assert_ok (&error);
6169 * mono_string_new_checked:
6170 * @text: a pointer to an utf8 string
6171 * @merror: set on error
6173 * Returns: A newly created string object which contains @text.
6174 * On error returns NULL and sets @merror.
6177 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6179 MONO_REQ_GC_UNSAFE_MODE;
6181 GError *eg_error = NULL;
6182 MonoString *o = NULL;
6184 glong items_written;
6187 mono_error_init (error);
6191 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6194 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6196 g_error_free (eg_error);
6200 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6205 MonoString *o = NULL;
6207 if (!g_utf8_validate (text, -1, &end)) {
6208 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6212 len = g_utf8_strlen (text, -1);
6213 o = mono_string_new_size_checked (domain, len, error);
6216 str = mono_string_chars (o);
6218 while (text < end) {
6219 *str++ = g_utf8_get_char (text);
6220 text = g_utf8_next_char (text);
6229 * mono_string_new_wrapper:
6230 * @text: pointer to utf8 characters.
6232 * Helper function to create a string object from @text in the current domain.
6235 mono_string_new_wrapper (const char *text)
6237 MONO_REQ_GC_UNSAFE_MODE;
6239 MonoDomain *domain = mono_domain_get ();
6242 return mono_string_new (domain, text);
6249 * @class: the class of the value
6250 * @value: a pointer to the unboxed data
6252 * Returns: A newly created object which contains @value.
6255 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6258 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6259 mono_error_cleanup (&error);
6264 * mono_value_box_checked:
6265 * @domain: the domain of the new object
6266 * @class: the class of the value
6267 * @value: a pointer to the unboxed data
6268 * @error: set on error
6270 * Returns: A newly created object which contains @value. On failure
6271 * returns NULL and sets @error.
6274 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6276 MONO_REQ_GC_UNSAFE_MODE;
6281 mono_error_init (error);
6283 g_assert (klass->valuetype);
6284 if (mono_class_is_nullable (klass))
6285 return mono_nullable_box ((guint8 *)value, klass, error);
6287 vtable = mono_class_vtable (domain, klass);
6290 size = mono_class_instance_size (klass);
6291 res = mono_object_new_alloc_specific_checked (vtable, error);
6292 return_val_if_nok (error, NULL);
6294 size = size - sizeof (MonoObject);
6297 g_assert (size == mono_class_value_size (klass, NULL));
6298 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6300 #if NO_UNALIGNED_ACCESS
6301 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6305 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6308 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6311 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6314 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6317 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6321 if (klass->has_finalize) {
6322 mono_object_register_finalizer (res);
6323 return_val_if_nok (error, NULL);
6330 * @dest: destination pointer
6331 * @src: source pointer
6332 * @klass: a valuetype class
6334 * Copy a valuetype from @src to @dest. This function must be used
6335 * when @klass contains references fields.
6338 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6340 MONO_REQ_GC_UNSAFE_MODE;
6342 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6346 * mono_value_copy_array:
6347 * @dest: destination array
6348 * @dest_idx: index in the @dest array
6349 * @src: source pointer
6350 * @count: number of items
6352 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6353 * This function must be used when @klass contains references fields.
6354 * Overlap is handled.
6357 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6359 MONO_REQ_GC_UNSAFE_MODE;
6361 int size = mono_array_element_size (dest->obj.vtable->klass);
6362 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6363 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6364 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6368 * mono_object_get_domain:
6369 * @obj: object to query
6371 * Returns: the MonoDomain where the object is hosted
6374 mono_object_get_domain (MonoObject *obj)
6376 MONO_REQ_GC_UNSAFE_MODE;
6378 return mono_object_domain (obj);
6382 * mono_object_get_class:
6383 * @obj: object to query
6385 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6387 * Returns: the MonoClass of the object.
6390 mono_object_get_class (MonoObject *obj)
6392 MONO_REQ_GC_UNSAFE_MODE;
6394 return mono_object_class (obj);
6397 * mono_object_get_size:
6398 * @o: object to query
6400 * Returns: the size, in bytes, of @o
6403 mono_object_get_size (MonoObject* o)
6405 MONO_REQ_GC_UNSAFE_MODE;
6407 MonoClass* klass = mono_object_class (o);
6408 if (klass == mono_defaults.string_class) {
6409 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6410 } else if (o->vtable->rank) {
6411 MonoArray *array = (MonoArray*)o;
6412 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6413 if (array->bounds) {
6416 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6420 return mono_class_instance_size (klass);
6425 * mono_object_unbox:
6426 * @obj: object to unbox
6428 * Returns: a pointer to the start of the valuetype boxed in this
6431 * This method will assert if the object passed is not a valuetype.
6434 mono_object_unbox (MonoObject *obj)
6436 MONO_REQ_GC_UNSAFE_MODE;
6438 /* add assert for valuetypes? */
6439 g_assert (obj->vtable->klass->valuetype);
6440 return ((char*)obj) + sizeof (MonoObject);
6444 * mono_object_isinst:
6446 * @klass: a pointer to a class
6448 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6451 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6453 MONO_REQ_GC_UNSAFE_MODE;
6456 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6457 mono_error_cleanup (&error);
6463 * mono_object_isinst_checked:
6465 * @klass: a pointer to a class
6466 * @error: set on error
6468 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6469 * On failure returns NULL and sets @error.
6472 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6474 MONO_REQ_GC_UNSAFE_MODE;
6476 mono_error_init (error);
6478 MonoObject *result = NULL;
6481 mono_class_init (klass);
6483 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6484 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6491 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6495 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6497 MONO_REQ_GC_UNSAFE_MODE;
6500 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6501 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6506 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6508 MONO_REQ_GC_UNSAFE_MODE;
6512 mono_error_init (error);
6519 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6520 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6524 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6525 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6528 MonoClass *oklass = vt->klass;
6529 if (mono_class_is_transparent_proxy (oklass))
6530 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6532 mono_class_setup_supertypes (klass);
6533 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6536 #ifndef DISABLE_REMOTING
6537 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6539 MonoDomain *domain = mono_domain_get ();
6541 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6542 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6543 MonoMethod *im = NULL;
6546 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6548 mono_error_set_not_supported (error, "Linked away.");
6551 im = mono_object_get_virtual_method (rp, im);
6554 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6555 return_val_if_nok (error, NULL);
6558 res = mono_runtime_invoke_checked (im, rp, pa, error);
6559 return_val_if_nok (error, NULL);
6561 if (*(MonoBoolean *) mono_object_unbox(res)) {
6562 /* Update the vtable of the remote type, so it can safely cast to this new type */
6563 mono_upgrade_remote_class (domain, obj, klass, error);
6564 return_val_if_nok (error, NULL);
6568 #endif /* DISABLE_REMOTING */
6573 * mono_object_castclass_mbyref:
6575 * @klass: a pointer to a class
6577 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6580 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6582 MONO_REQ_GC_UNSAFE_MODE;
6585 if (!obj) return NULL;
6586 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6587 mono_error_cleanup (&error);
6592 MonoDomain *orig_domain;
6598 str_lookup (MonoDomain *domain, gpointer user_data)
6600 MONO_REQ_GC_UNSAFE_MODE;
6602 LDStrInfo *info = (LDStrInfo *)user_data;
6603 if (info->res || domain == info->orig_domain)
6605 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6609 mono_string_get_pinned (MonoString *str, MonoError *error)
6611 MONO_REQ_GC_UNSAFE_MODE;
6613 mono_error_init (error);
6615 /* We only need to make a pinned version of a string if this is a moving GC */
6616 if (!mono_gc_is_moving ())
6620 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6621 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6623 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6624 news->length = mono_string_length (str);
6626 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6632 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6634 MONO_REQ_GC_UNSAFE_MODE;
6636 MonoGHashTable *ldstr_table;
6637 MonoString *s, *res;
6640 mono_error_init (error);
6642 domain = ((MonoObject *)str)->vtable->domain;
6643 ldstr_table = domain->ldstr_table;
6645 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6651 /* Allocate outside the lock */
6653 s = mono_string_get_pinned (str, error);
6654 return_val_if_nok (error, NULL);
6657 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6662 mono_g_hash_table_insert (ldstr_table, s, s);
6667 LDStrInfo ldstr_info;
6668 ldstr_info.orig_domain = domain;
6669 ldstr_info.ins = str;
6670 ldstr_info.res = NULL;
6672 mono_domain_foreach (str_lookup, &ldstr_info);
6673 if (ldstr_info.res) {
6675 * the string was already interned in some other domain:
6676 * intern it in the current one as well.
6678 mono_g_hash_table_insert (ldstr_table, str, str);
6688 * mono_string_is_interned:
6689 * @o: String to probe
6691 * Returns whether the string has been interned.
6694 mono_string_is_interned (MonoString *o)
6697 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6698 /* This function does not fail. */
6699 mono_error_assert_ok (&error);
6704 * mono_string_intern:
6705 * @o: String to intern
6707 * Interns the string passed.
6708 * Returns: The interned string.
6711 mono_string_intern (MonoString *str)
6714 MonoString *result = mono_string_intern_checked (str, &error);
6715 mono_error_assert_ok (&error);
6720 * mono_string_intern_checked:
6721 * @o: String to intern
6722 * @error: set on error.
6724 * Interns the string passed.
6725 * Returns: The interned string. On failure returns NULL and sets @error
6728 mono_string_intern_checked (MonoString *str, MonoError *error)
6730 MONO_REQ_GC_UNSAFE_MODE;
6732 mono_error_init (error);
6734 return mono_string_is_interned_lookup (str, TRUE, error);
6739 * @domain: the domain where the string will be used.
6740 * @image: a metadata context
6741 * @idx: index into the user string table.
6743 * Implementation for the ldstr opcode.
6744 * Returns: a loaded string from the @image/@idx combination.
6747 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6750 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6751 mono_error_cleanup (&error);
6756 * mono_ldstr_checked:
6757 * @domain: the domain where the string will be used.
6758 * @image: a metadata context
6759 * @idx: index into the user string table.
6760 * @error: set on error.
6762 * Implementation for the ldstr opcode.
6763 * Returns: a loaded string from the @image/@idx combination.
6764 * On failure returns NULL and sets @error.
6767 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6769 MONO_REQ_GC_UNSAFE_MODE;
6770 mono_error_init (error);
6772 if (image->dynamic) {
6773 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6776 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6777 return NULL; /*FIXME we should probably be raising an exception here*/
6778 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6784 * mono_ldstr_metadata_sig
6785 * @domain: the domain for the string
6786 * @sig: the signature of a metadata string
6787 * @error: set on error
6789 * Returns: a MonoString for a string stored in the metadata. On
6790 * failure returns NULL and sets @error.
6793 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6795 MONO_REQ_GC_UNSAFE_MODE;
6797 mono_error_init (error);
6798 const char *str = sig;
6799 MonoString *o, *interned;
6802 len2 = mono_metadata_decode_blob_size (str, &str);
6805 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6806 return_val_if_nok (error, NULL);
6807 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6810 guint16 *p2 = (guint16*)mono_string_chars (o);
6811 for (i = 0; i < len2; ++i) {
6812 *p2 = GUINT16_FROM_LE (*p2);
6818 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6821 return interned; /* o will get garbage collected */
6823 o = mono_string_get_pinned (o, error);
6826 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6828 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6840 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6844 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6850 GError *gerror = NULL;
6852 mono_error_init (error);
6854 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6855 return NULL; /*FIXME we should probably be raising an exception here*/
6856 str = mono_metadata_user_string (image, idx);
6858 len2 = mono_metadata_decode_blob_size (str, &str);
6861 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6863 mono_error_set_argument (error, "string", "%s", gerror->message);
6864 g_error_free (gerror);
6867 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6868 if (len2 > written) {
6869 /* allocate the total length and copy the part of the string that has been converted */
6870 char *as2 = (char *)g_malloc0 (len2);
6871 memcpy (as2, as, written);
6880 * mono_string_to_utf8:
6881 * @s: a System.String
6883 * Returns the UTF8 representation for @s.
6884 * The resulting buffer needs to be freed with mono_free().
6886 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6889 mono_string_to_utf8 (MonoString *s)
6891 MONO_REQ_GC_UNSAFE_MODE;
6894 char *result = mono_string_to_utf8_checked (s, &error);
6896 if (!is_ok (&error)) {
6897 mono_error_cleanup (&error);
6904 * mono_string_to_utf8_checked:
6905 * @s: a System.String
6906 * @error: a MonoError.
6908 * Converts a MonoString to its UTF8 representation. May fail; check
6909 * @error to determine whether the conversion was successful.
6910 * The resulting buffer should be freed with mono_free().
6913 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6915 MONO_REQ_GC_UNSAFE_MODE;
6919 GError *gerror = NULL;
6921 mono_error_init (error);
6927 return g_strdup ("");
6929 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6931 mono_error_set_argument (error, "string", "%s", gerror->message);
6932 g_error_free (gerror);
6935 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6936 if (s->length > written) {
6937 /* allocate the total length and copy the part of the string that has been converted */
6938 char *as2 = (char *)g_malloc0 (s->length);
6939 memcpy (as2, as, written);
6948 * mono_string_to_utf8_ignore:
6951 * Converts a MonoString to its UTF8 representation. Will ignore
6952 * invalid surrogate pairs.
6953 * The resulting buffer should be freed with mono_free().
6957 mono_string_to_utf8_ignore (MonoString *s)
6959 MONO_REQ_GC_UNSAFE_MODE;
6968 return g_strdup ("");
6970 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6972 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6973 if (s->length > written) {
6974 /* allocate the total length and copy the part of the string that has been converted */
6975 char *as2 = (char *)g_malloc0 (s->length);
6976 memcpy (as2, as, written);
6985 * mono_string_to_utf8_image_ignore:
6986 * @s: a System.String
6988 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6991 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6993 MONO_REQ_GC_UNSAFE_MODE;
6995 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6999 * mono_string_to_utf8_mp_ignore:
7000 * @s: a System.String
7002 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7005 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7007 MONO_REQ_GC_UNSAFE_MODE;
7009 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7014 * mono_string_to_utf16:
7017 * Return an null-terminated array of the utf-16 chars
7018 * contained in @s. The result must be freed with g_free().
7019 * This is a temporary helper until our string implementation
7020 * is reworked to always include the null terminating char.
7023 mono_string_to_utf16 (MonoString *s)
7025 MONO_REQ_GC_UNSAFE_MODE;
7032 as = (char *)g_malloc ((s->length * 2) + 2);
7033 as [(s->length * 2)] = '\0';
7034 as [(s->length * 2) + 1] = '\0';
7037 return (gunichar2 *)(as);
7040 memcpy (as, mono_string_chars(s), s->length * 2);
7041 return (gunichar2 *)(as);
7045 * mono_string_to_utf32:
7048 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7049 * contained in @s. The result must be freed with g_free().
7052 mono_string_to_utf32 (MonoString *s)
7054 MONO_REQ_GC_UNSAFE_MODE;
7056 mono_unichar4 *utf32_output = NULL;
7057 GError *error = NULL;
7058 glong items_written;
7063 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7066 g_error_free (error);
7068 return utf32_output;
7072 * mono_string_from_utf16:
7073 * @data: the UTF16 string (LPWSTR) to convert
7075 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7077 * Returns: a MonoString.
7080 mono_string_from_utf16 (gunichar2 *data)
7083 MonoString *result = mono_string_from_utf16_checked (data, &error);
7084 mono_error_cleanup (&error);
7089 * mono_string_from_utf16_checked:
7090 * @data: the UTF16 string (LPWSTR) to convert
7091 * @error: set on error
7093 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7095 * Returns: a MonoString. On failure sets @error and returns NULL.
7098 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7101 MONO_REQ_GC_UNSAFE_MODE;
7103 mono_error_init (error);
7104 MonoDomain *domain = mono_domain_get ();
7110 while (data [len]) len++;
7112 return mono_string_new_utf16_checked (domain, data, len, error);
7116 * mono_string_from_utf32:
7117 * @data: the UTF32 string (LPWSTR) to convert
7119 * Converts a UTF32 (UCS-4)to a MonoString.
7121 * Returns: a MonoString.
7124 mono_string_from_utf32 (mono_unichar4 *data)
7127 MonoString *result = mono_string_from_utf32_checked (data, &error);
7128 mono_error_cleanup (&error);
7133 * mono_string_from_utf32_checked:
7134 * @data: the UTF32 string (LPWSTR) to convert
7135 * @error: set on error
7137 * Converts a UTF32 (UCS-4)to a MonoString.
7139 * Returns: a MonoString. On failure returns NULL and sets @error.
7142 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7144 MONO_REQ_GC_UNSAFE_MODE;
7146 mono_error_init (error);
7147 MonoString* result = NULL;
7148 mono_unichar2 *utf16_output = NULL;
7149 GError *gerror = NULL;
7150 glong items_written;
7156 while (data [len]) len++;
7158 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7161 g_error_free (gerror);
7163 result = mono_string_from_utf16_checked (utf16_output, error);
7164 g_free (utf16_output);
7169 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7171 MONO_REQ_GC_UNSAFE_MODE;
7178 r = mono_string_to_utf8_ignore (s);
7180 r = mono_string_to_utf8_checked (s, error);
7181 if (!mono_error_ok (error))
7188 len = strlen (r) + 1;
7190 mp_s = (char *)mono_mempool_alloc (mp, len);
7192 mp_s = (char *)mono_image_alloc (image, len);
7194 memcpy (mp_s, r, len);
7202 * mono_string_to_utf8_image:
7203 * @s: a System.String
7205 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7208 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7210 MONO_REQ_GC_UNSAFE_MODE;
7212 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7216 * mono_string_to_utf8_mp:
7217 * @s: a System.String
7219 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7222 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7224 MONO_REQ_GC_UNSAFE_MODE;
7226 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7230 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7233 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7235 eh_callbacks = *cbs;
7238 MonoRuntimeExceptionHandlingCallbacks *
7239 mono_get_eh_callbacks (void)
7241 return &eh_callbacks;
7245 * mono_raise_exception:
7246 * @ex: exception object
7248 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7251 mono_raise_exception (MonoException *ex)
7253 MONO_REQ_GC_UNSAFE_MODE;
7256 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7257 * that will cause gcc to omit the function epilog, causing problems when
7258 * the JIT tries to walk the stack, since the return address on the stack
7259 * will point into the next function in the executable, not this one.
7261 eh_callbacks.mono_raise_exception (ex);
7265 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7267 MONO_REQ_GC_UNSAFE_MODE;
7269 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7273 * mono_wait_handle_new:
7274 * @domain: Domain where the object will be created
7275 * @handle: Handle for the wait handle
7276 * @error: set on error.
7278 * Returns: A new MonoWaitHandle created in the given domain for the
7279 * given handle. On failure returns NULL and sets @rror.
7282 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7284 MONO_REQ_GC_UNSAFE_MODE;
7286 MonoWaitHandle *res;
7287 gpointer params [1];
7288 static MonoMethod *handle_set;
7290 mono_error_init (error);
7291 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7292 return_val_if_nok (error, NULL);
7294 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7296 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7298 params [0] = &handle;
7300 mono_runtime_invoke_checked (handle_set, res, params, error);
7305 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7307 MONO_REQ_GC_UNSAFE_MODE;
7309 static MonoClassField *f_safe_handle = NULL;
7312 if (!f_safe_handle) {
7313 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7314 g_assert (f_safe_handle);
7317 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7323 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7325 MONO_REQ_GC_UNSAFE_MODE;
7327 RuntimeInvokeFunction runtime_invoke;
7329 mono_error_init (error);
7331 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7332 MonoMethod *method = mono_get_context_capture_method ();
7333 MonoMethod *wrapper;
7336 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7337 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7338 return_val_if_nok (error, NULL);
7339 domain->capture_context_method = mono_compile_method_checked (method, error);
7340 return_val_if_nok (error, NULL);
7343 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7345 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7348 * mono_async_result_new:
7349 * @domain:domain where the object will be created.
7350 * @handle: wait handle.
7351 * @state: state to pass to AsyncResult
7352 * @data: C closure data.
7353 * @error: set on error.
7355 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7356 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7357 * On failure returns NULL and sets @error.
7361 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7363 MONO_REQ_GC_UNSAFE_MODE;
7365 mono_error_init (error);
7366 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7367 return_val_if_nok (error, NULL);
7368 MonoObject *context = mono_runtime_capture_context (domain, error);
7369 return_val_if_nok (error, NULL);
7370 /* we must capture the execution context from the original thread */
7372 MONO_OBJECT_SETREF (res, execution_context, context);
7373 /* note: result may be null if the flow is suppressed */
7376 res->data = (void **)data;
7377 MONO_OBJECT_SETREF (res, object_data, object_data);
7378 MONO_OBJECT_SETREF (res, async_state, state);
7379 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7380 return_val_if_nok (error, NULL);
7382 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7384 res->sync_completed = FALSE;
7385 res->completed = FALSE;
7391 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7393 MONO_REQ_GC_UNSAFE_MODE;
7400 g_assert (ares->async_delegate);
7402 ac = (MonoAsyncCall*) ares->object_data;
7404 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7405 if (mono_error_set_pending_exception (&error))
7408 gpointer wait_event = NULL;
7410 ac->msg->exc = NULL;
7412 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7414 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7415 mono_threads_begin_abort_protected_block ();
7417 if (!ac->msg->exc) {
7418 MonoException *ex = mono_error_convert_to_exception (&error);
7419 ac->msg->exc = (MonoObject *)ex;
7421 mono_error_cleanup (&error);
7424 MONO_OBJECT_SETREF (ac, res, res);
7426 mono_monitor_enter ((MonoObject*) ares);
7427 ares->completed = 1;
7429 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7430 mono_monitor_exit ((MonoObject*) ares);
7432 if (wait_event != NULL)
7433 mono_w32event_set (wait_event);
7435 mono_error_init (&error); //the else branch would leave it in an undefined state
7437 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7439 mono_threads_end_abort_protected_block ();
7441 if (mono_error_set_pending_exception (&error))
7449 mono_message_init (MonoDomain *domain,
7450 MonoMethodMessage *this_obj,
7451 MonoReflectionMethod *method,
7452 MonoArray *out_args,
7455 MONO_REQ_GC_UNSAFE_MODE;
7457 static MonoMethod *init_message_method = NULL;
7459 if (!init_message_method) {
7460 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7461 g_assert (init_message_method != NULL);
7464 mono_error_init (error);
7465 /* FIXME set domain instead? */
7466 g_assert (domain == mono_domain_get ());
7473 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7474 return is_ok (error);
7477 #ifndef DISABLE_REMOTING
7479 * mono_remoting_invoke:
7480 * @real_proxy: pointer to a RealProxy object
7481 * @msg: The MonoMethodMessage to execute
7482 * @exc: used to store exceptions
7483 * @out_args: used to store output arguments
7485 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7486 * IMessage interface and it is not trivial to extract results from there. So
7487 * we call an helper method PrivateInvoke instead of calling
7488 * RealProxy::Invoke() directly.
7490 * Returns: the result object.
7493 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7495 MONO_REQ_GC_UNSAFE_MODE;
7498 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7503 mono_error_init (error);
7505 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7508 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7510 mono_error_set_not_supported (error, "Linked away.");
7513 real_proxy->vtable->domain->private_invoke_method = im;
7516 pa [0] = real_proxy;
7521 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7522 return_val_if_nok (error, NULL);
7529 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7530 MonoObject **exc, MonoArray **out_args, MonoError *error)
7532 MONO_REQ_GC_UNSAFE_MODE;
7534 static MonoClass *object_array_klass;
7535 mono_error_init (error);
7539 MonoMethodSignature *sig;
7541 int i, j, outarg_count = 0;
7543 #ifndef DISABLE_REMOTING
7544 if (target && mono_object_is_transparent_proxy (target)) {
7545 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7546 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7547 target = tp->rp->unwrapped_server;
7549 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7554 domain = mono_domain_get ();
7555 method = msg->method->method;
7556 sig = mono_method_signature (method);
7558 for (i = 0; i < sig->param_count; i++) {
7559 if (sig->params [i]->byref)
7563 if (!object_array_klass) {
7566 klass = mono_array_class_get (mono_defaults.object_class, 1);
7569 mono_memory_barrier ();
7570 object_array_klass = klass;
7573 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7574 return_val_if_nok (error, NULL);
7576 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7579 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7580 return_val_if_nok (error, NULL);
7582 for (i = 0, j = 0; i < sig->param_count; i++) {
7583 if (sig->params [i]->byref) {
7585 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7586 mono_array_setref (*out_args, j, arg);
7595 * prepare_to_string_method:
7597 * @target: Set to @obj or unboxed value if a valuetype
7599 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7602 prepare_to_string_method (MonoObject *obj, void **target)
7604 MONO_REQ_GC_UNSAFE_MODE;
7606 static MonoMethod *to_string = NULL;
7614 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7616 method = mono_object_get_virtual_method (obj, to_string);
7618 // Unbox value type if needed
7619 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7620 *target = mono_object_unbox (obj);
7626 * mono_object_to_string:
7628 * @exc: Any exception thrown by ToString (). May be NULL.
7630 * Returns: the result of calling ToString () on an object.
7633 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7636 MonoString *s = NULL;
7638 MonoMethod *method = prepare_to_string_method (obj, &target);
7640 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7641 if (*exc == NULL && !mono_error_ok (&error))
7642 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7644 mono_error_cleanup (&error);
7646 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7647 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7654 * mono_object_to_string_checked:
7656 * @error: Set on error.
7658 * Returns: the result of calling ToString () on an object. If the
7659 * method cannot be invoked or if it raises an exception, sets @error
7663 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7665 mono_error_init (error);
7667 MonoMethod *method = prepare_to_string_method (obj, &target);
7668 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7672 * mono_object_try_to_string:
7674 * @exc: Any exception thrown by ToString (). Must not be NULL.
7675 * @error: Set if method cannot be invoked.
7677 * Returns: the result of calling ToString () on an object. If the
7678 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7682 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7685 mono_error_init (error);
7687 MonoMethod *method = prepare_to_string_method (obj, &target);
7688 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7694 * mono_print_unhandled_exception:
7695 * @exc: The exception
7697 * Prints the unhandled exception.
7700 mono_print_unhandled_exception (MonoObject *exc)
7702 MONO_REQ_GC_UNSAFE_MODE;
7705 char *message = (char*)"";
7706 gboolean free_message = FALSE;
7709 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7710 message = g_strdup ("OutOfMemoryException");
7711 free_message = TRUE;
7712 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7713 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7714 free_message = TRUE;
7717 if (((MonoException*)exc)->native_trace_ips) {
7718 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7719 free_message = TRUE;
7721 MonoObject *other_exc = NULL;
7722 str = mono_object_try_to_string (exc, &other_exc, &error);
7723 if (other_exc == NULL && !is_ok (&error))
7724 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7726 mono_error_cleanup (&error);
7728 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7729 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7731 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7732 original_backtrace, nested_backtrace);
7734 g_free (original_backtrace);
7735 g_free (nested_backtrace);
7736 free_message = TRUE;
7738 message = mono_string_to_utf8_checked (str, &error);
7739 if (!mono_error_ok (&error)) {
7740 mono_error_cleanup (&error);
7741 message = (char *) "";
7743 free_message = TRUE;
7750 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7751 * exc->vtable->klass->name, message);
7753 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7760 * mono_delegate_ctor_with_method:
7761 * @this: pointer to an uninitialized delegate object
7762 * @target: target object
7763 * @addr: pointer to native code
7765 * @error: set on error.
7767 * Initialize a delegate and sets a specific method, not the one
7768 * associated with addr. This is useful when sharing generic code.
7769 * In that case addr will most probably not be associated with the
7770 * correct instantiation of the method.
7771 * On failure returns FALSE and sets @error.
7774 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7776 MONO_REQ_GC_UNSAFE_MODE;
7778 mono_error_init (error);
7779 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7781 g_assert (this_obj);
7784 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7787 delegate->method = method;
7789 mono_stats.delegate_creations++;
7791 #ifndef DISABLE_REMOTING
7792 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7794 method = mono_marshal_get_remoting_invoke (method);
7795 delegate->method_ptr = mono_compile_method_checked (method, error);
7796 return_val_if_nok (error, FALSE);
7797 MONO_OBJECT_SETREF (delegate, target, target);
7801 delegate->method_ptr = addr;
7802 MONO_OBJECT_SETREF (delegate, target, target);
7805 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7806 if (callbacks.init_delegate)
7807 callbacks.init_delegate (delegate);
7812 * mono_delegate_ctor:
7813 * @this: pointer to an uninitialized delegate object
7814 * @target: target object
7815 * @addr: pointer to native code
7816 * @error: set on error.
7818 * This is used to initialize a delegate.
7819 * On failure returns FALSE and sets @error.
7822 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7824 MONO_REQ_GC_UNSAFE_MODE;
7826 mono_error_init (error);
7827 MonoDomain *domain = mono_domain_get ();
7829 MonoMethod *method = NULL;
7833 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7835 if (!ji && domain != mono_get_root_domain ())
7836 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7838 method = mono_jit_info_get_method (ji);
7839 g_assert (!method->klass->generic_container);
7842 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7846 * mono_method_call_message_new:
7847 * @method: method to encapsulate
7848 * @params: parameters to the method
7849 * @invoke: optional, delegate invoke.
7850 * @cb: async callback delegate.
7851 * @state: state passed to the async callback.
7852 * @error: set on error.
7854 * Translates arguments pointers into a MonoMethodMessage.
7855 * On failure returns NULL and sets @error.
7858 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7859 MonoDelegate **cb, MonoObject **state, MonoError *error)
7861 MONO_REQ_GC_UNSAFE_MODE;
7863 mono_error_init (error);
7865 MonoDomain *domain = mono_domain_get ();
7866 MonoMethodSignature *sig = mono_method_signature (method);
7867 MonoMethodMessage *msg;
7870 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7871 return_val_if_nok (error, NULL);
7874 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7875 return_val_if_nok (error, NULL);
7876 mono_message_init (domain, msg, rm, NULL, error);
7877 return_val_if_nok (error, NULL);
7878 count = sig->param_count - 2;
7880 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7881 return_val_if_nok (error, NULL);
7882 mono_message_init (domain, msg, rm, NULL, error);
7883 return_val_if_nok (error, NULL);
7884 count = sig->param_count;
7887 for (i = 0; i < count; i++) {
7892 if (sig->params [i]->byref)
7893 vpos = *((gpointer *)params [i]);
7897 klass = mono_class_from_mono_type (sig->params [i]);
7899 if (klass->valuetype) {
7900 arg = mono_value_box_checked (domain, klass, vpos, error);
7901 return_val_if_nok (error, NULL);
7903 arg = *((MonoObject **)vpos);
7905 mono_array_setref (msg->args, i, arg);
7908 if (cb != NULL && state != NULL) {
7909 *cb = *((MonoDelegate **)params [i]);
7911 *state = *((MonoObject **)params [i]);
7918 * mono_method_return_message_restore:
7920 * Restore results from message based processing back to arguments pointers
7923 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7925 MONO_REQ_GC_UNSAFE_MODE;
7927 mono_error_init (error);
7929 MonoMethodSignature *sig = mono_method_signature (method);
7930 int i, j, type, size, out_len;
7932 if (out_args == NULL)
7934 out_len = mono_array_length (out_args);
7938 for (i = 0, j = 0; i < sig->param_count; i++) {
7939 MonoType *pt = sig->params [i];
7944 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7948 arg = (char *)mono_array_get (out_args, gpointer, j);
7951 g_assert (type != MONO_TYPE_VOID);
7953 if (MONO_TYPE_IS_REFERENCE (pt)) {
7954 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7957 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7958 size = mono_class_value_size (klass, NULL);
7959 if (klass->has_references)
7960 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7962 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7964 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7965 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7974 #ifndef DISABLE_REMOTING
7977 * mono_load_remote_field:
7978 * @this: pointer to an object
7979 * @klass: klass of the object containing @field
7980 * @field: the field to load
7981 * @res: a storage to store the result
7983 * This method is called by the runtime on attempts to load fields of
7984 * transparent proxy objects. @this points to such TP, @klass is the class of
7985 * the object containing @field. @res is a storage location which can be
7986 * used to store the result.
7988 * Returns: an address pointing to the value of field.
7991 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7994 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7995 mono_error_cleanup (&error);
8000 * mono_load_remote_field_checked:
8001 * @this: pointer to an object
8002 * @klass: klass of the object containing @field
8003 * @field: the field to load
8004 * @res: a storage to store the result
8005 * @error: set on error
8007 * This method is called by the runtime on attempts to load fields of
8008 * transparent proxy objects. @this points to such TP, @klass is the class of
8009 * the object containing @field. @res is a storage location which can be
8010 * used to store the result.
8012 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8015 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8017 MONO_REQ_GC_UNSAFE_MODE;
8019 static MonoMethod *getter = NULL;
8021 mono_error_init (error);
8023 MonoDomain *domain = mono_domain_get ();
8024 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8025 MonoClass *field_class;
8026 MonoMethodMessage *msg;
8027 MonoArray *out_args;
8031 g_assert (mono_object_is_transparent_proxy (this_obj));
8032 g_assert (res != NULL);
8034 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8035 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8040 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8042 mono_error_set_not_supported (error, "Linked away.");
8047 field_class = mono_class_from_mono_type (field->type);
8049 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8050 return_val_if_nok (error, NULL);
8051 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8052 return_val_if_nok (error, NULL);
8053 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8054 return_val_if_nok (error, NULL);
8055 mono_message_init (domain, msg, rm, out_args, error);
8056 return_val_if_nok (error, NULL);
8058 full_name = mono_type_get_full_name (klass);
8059 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8060 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8063 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8064 return_val_if_nok (error, NULL);
8067 mono_error_set_exception_instance (error, (MonoException *)exc);
8071 if (mono_array_length (out_args) == 0)
8074 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8076 if (field_class->valuetype) {
8077 return ((char *)*res) + sizeof (MonoObject);
8083 * mono_load_remote_field_new:
8088 * Missing documentation.
8091 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8095 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8096 mono_error_cleanup (&error);
8101 * mono_load_remote_field_new_checked:
8102 * @this: pointer to an object
8103 * @klass: klass of the object containing @field
8104 * @field: the field to load
8105 * @error: set on error.
8107 * This method is called by the runtime on attempts to load fields of
8108 * transparent proxy objects. @this points to such TP, @klass is the class of
8109 * the object containing @field.
8111 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8114 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8116 MONO_REQ_GC_UNSAFE_MODE;
8118 mono_error_init (error);
8120 static MonoMethod *tp_load = NULL;
8122 g_assert (mono_object_is_transparent_proxy (this_obj));
8125 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8127 mono_error_set_not_supported (error, "Linked away.");
8132 /* MonoType *type = mono_class_get_type (klass); */
8138 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8142 * mono_store_remote_field:
8143 * @this_obj: pointer to an object
8144 * @klass: klass of the object containing @field
8145 * @field: the field to load
8146 * @val: the value/object to store
8148 * This method is called by the runtime on attempts to store fields of
8149 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8150 * the object containing @field. @val is the new value to store in @field.
8153 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8156 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8157 mono_error_cleanup (&error);
8161 * mono_store_remote_field_checked:
8162 * @this_obj: pointer to an object
8163 * @klass: klass of the object containing @field
8164 * @field: the field to load
8165 * @val: the value/object to store
8166 * @error: set on error
8168 * This method is called by the runtime on attempts to store fields of
8169 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8170 * the object containing @field. @val is the new value to store in @field.
8172 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8175 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8178 MONO_REQ_GC_UNSAFE_MODE;
8180 mono_error_init (error);
8182 MonoDomain *domain = mono_domain_get ();
8183 MonoClass *field_class;
8186 g_assert (mono_object_is_transparent_proxy (this_obj));
8188 field_class = mono_class_from_mono_type (field->type);
8190 if (field_class->valuetype) {
8191 arg = mono_value_box_checked (domain, field_class, val, error);
8192 return_val_if_nok (error, FALSE);
8194 arg = *((MonoObject**)val);
8197 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8201 * mono_store_remote_field_new:
8207 * Missing documentation
8210 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8213 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8214 mono_error_cleanup (&error);
8218 * mono_store_remote_field_new_checked:
8225 * Missing documentation
8228 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8230 MONO_REQ_GC_UNSAFE_MODE;
8232 static MonoMethod *tp_store = NULL;
8234 mono_error_init (error);
8236 g_assert (mono_object_is_transparent_proxy (this_obj));
8239 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8241 mono_error_set_not_supported (error, "Linked away.");
8251 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8252 return is_ok (error);
8257 * mono_create_ftnptr:
8259 * Given a function address, create a function descriptor for it.
8260 * This is only needed on some platforms.
8263 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8265 return callbacks.create_ftnptr (domain, addr);
8269 * mono_get_addr_from_ftnptr:
8271 * Given a pointer to a function descriptor, return the function address.
8272 * This is only needed on some platforms.
8275 mono_get_addr_from_ftnptr (gpointer descr)
8277 return callbacks.get_addr_from_ftnptr (descr);
8281 * mono_string_chars:
8284 * Returns a pointer to the UCS16 characters stored in the MonoString
8287 mono_string_chars (MonoString *s)
8289 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8295 * mono_string_length:
8298 * Returns the lenght in characters of the string
8301 mono_string_length (MonoString *s)
8303 MONO_REQ_GC_UNSAFE_MODE;
8309 * mono_array_length:
8310 * @array: a MonoArray*
8312 * Returns the total number of elements in the array. This works for
8313 * both vectors and multidimensional arrays.
8316 mono_array_length (MonoArray *array)
8318 MONO_REQ_GC_UNSAFE_MODE;
8320 return array->max_length;
8324 * mono_array_addr_with_size:
8325 * @array: a MonoArray*
8326 * @size: size of the array elements
8327 * @idx: index into the array
8329 * Use this function to obtain the address for the @idx item on the
8330 * @array containing elements of size @size.
8332 * This method performs no bounds checking or type checking.
8334 * Returns the address of the @idx element in the array.
8337 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8339 MONO_REQ_GC_UNSAFE_MODE;
8341 return ((char*)(array)->vector) + size * idx;
8346 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8348 MonoDomain *domain = mono_domain_get ();
8352 mono_error_init (error);
8356 len = g_list_length (list);
8357 res = mono_array_new_checked (domain, eclass, len, error);
8358 return_val_if_nok (error, NULL);
8360 for (i = 0; list; list = list->next, i++)
8361 mono_array_set (res, gpointer, i, list->data);
8368 * The following section is purely to declare prototypes and
8369 * document the API, as these C files are processed by our
8375 * @array: array to alter
8376 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8377 * @index: index into the array
8378 * @value: value to set
8380 * Value Type version: This sets the @index's element of the @array
8381 * with elements of size sizeof(type) to the provided @value.
8383 * This macro does not attempt to perform type checking or bounds checking.
8385 * Use this to set value types in a `MonoArray`.
8387 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8392 * mono_array_setref:
8393 * @array: array to alter
8394 * @index: index into the array
8395 * @value: value to set
8397 * Reference Type version: This sets the @index's element of the
8398 * @array with elements of size sizeof(type) to the provided @value.
8400 * This macro does not attempt to perform type checking or bounds checking.
8402 * Use this to reference types in a `MonoArray`.
8404 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8410 * @array: array on which to operate on
8411 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8412 * @index: index into the array
8414 * Use this macro to retrieve the @index element of an @array and
8415 * extract the value assuming that the elements of the array match
8416 * the provided type value.
8418 * This method can be used with both arrays holding value types and
8419 * reference types. For reference types, the @type parameter should
8420 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8422 * This macro does not attempt to perform type checking or bounds checking.
8424 * Returns: The element at the @index position in the @array.
8426 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)