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 int mcount = mono_class_get_method_count (iface);
1407 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1410 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1412 * The imt slot of the method is the same as for its declaring method,
1413 * see the comment in mono_method_get_imt_slot (), so we can
1414 * avoid inflating methods which will be discarded by
1415 * add_imt_builder_entry anyway.
1417 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1418 if (mono_method_get_imt_slot (method) != slot_num) {
1423 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1424 if (method->is_generic) {
1425 has_generic_virtual = TRUE;
1430 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1431 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1436 if (extra_interfaces) {
1437 int interface_offset = klass->vtable_size;
1439 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1440 MonoClass* iface = (MonoClass *)list_item->data;
1441 int method_slot_in_interface;
1442 int mcount = mono_class_get_method_count (iface);
1443 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1444 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1446 if (method->is_generic)
1447 has_generic_virtual = TRUE;
1448 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1450 interface_offset += mcount;
1453 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1454 /* overwrite the imt slot only if we're building all the entries or if
1455 * we're building this specific one
1457 if (slot_num < 0 || i == slot_num) {
1458 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1461 if (imt_builder [i]) {
1462 MonoImtBuilderEntry *entry;
1464 /* Link entries with imt_builder [i] */
1465 for (entry = entries; entry->next; entry = entry->next) {
1467 MonoMethod *method = (MonoMethod*)entry->key;
1468 char *method_name = mono_method_full_name (method, TRUE);
1469 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1470 g_free (method_name);
1473 entry->next = imt_builder [i];
1474 entries->children += imt_builder [i]->children + 1;
1476 imt_builder [i] = entries;
1479 if (has_generic_virtual || has_variant_iface) {
1481 * There might be collisions later when the the trampoline is expanded.
1483 imt_collisions_bitmap |= (1 << i);
1486 * The IMT trampoline might be called with an instance of one of the
1487 * generic virtual methods, so has to fallback to the IMT trampoline.
1489 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1491 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1494 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1498 if (imt_builder [i] != NULL) {
1499 int methods_in_slot = imt_builder [i]->children + 1;
1500 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1501 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1502 record_method_count_for_max_collisions = TRUE;
1504 method_count += methods_in_slot;
1508 mono_stats.imt_number_of_methods += method_count;
1509 if (record_method_count_for_max_collisions) {
1510 mono_stats.imt_method_count_when_max_collisions = method_count;
1513 for (i = 0; i < MONO_IMT_SIZE; i++) {
1514 MonoImtBuilderEntry* entry = imt_builder [i];
1515 while (entry != NULL) {
1516 MonoImtBuilderEntry* next = entry->next;
1521 g_free (imt_builder);
1522 /* we OR the bitmap since we may build just a single imt slot at a time */
1523 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1527 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1528 MONO_REQ_GC_NEUTRAL_MODE;
1530 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1534 * mono_vtable_build_imt_slot:
1535 * @vtable: virtual object table struct
1536 * @imt_slot: slot in the IMT table
1538 * Fill the given @imt_slot in the IMT table of @vtable with
1539 * a trampoline or a trampoline for the case of collisions.
1540 * This is part of the internal mono API.
1542 * LOCKING: Take the domain lock.
1545 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1547 MONO_REQ_GC_NEUTRAL_MODE;
1549 gpointer *imt = (gpointer*)vtable;
1550 imt -= MONO_IMT_SIZE;
1551 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1553 /* no support for extra interfaces: the proxy objects will need
1554 * to build the complete IMT
1555 * Update and heck needs to ahppen inside the proper domain lock, as all
1556 * the changes made to a MonoVTable.
1558 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1559 mono_domain_lock (vtable->domain);
1560 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1561 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1562 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1563 mono_domain_unlock (vtable->domain);
1564 mono_loader_unlock ();
1567 #define THUNK_THRESHOLD 10
1570 * mono_method_alloc_generic_virtual_trampoline:
1572 * @size: size in bytes
1574 * Allocs size bytes to be used for the code of a generic virtual
1575 * trampoline. It's either allocated from the domain's code manager or
1576 * reused from a previously invalidated piece.
1578 * LOCKING: The domain lock must be held.
1581 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1583 MONO_REQ_GC_NEUTRAL_MODE;
1585 static gboolean inited = FALSE;
1586 static int generic_virtual_trampolines_size = 0;
1589 mono_counters_register ("Generic virtual trampoline bytes",
1590 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1593 generic_virtual_trampolines_size += size;
1595 return mono_domain_code_reserve (domain, size);
1598 typedef struct _GenericVirtualCase {
1602 struct _GenericVirtualCase *next;
1603 } GenericVirtualCase;
1606 * get_generic_virtual_entries:
1608 * Return IMT entries for the generic virtual method instances and
1609 * variant interface methods for vtable slot
1612 static MonoImtBuilderEntry*
1613 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1615 MONO_REQ_GC_NEUTRAL_MODE;
1617 GenericVirtualCase *list;
1618 MonoImtBuilderEntry *entries;
1620 mono_domain_lock (domain);
1621 if (!domain->generic_virtual_cases)
1622 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1624 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1627 for (; list; list = list->next) {
1628 MonoImtBuilderEntry *entry;
1630 if (list->count < THUNK_THRESHOLD)
1633 entry = g_new0 (MonoImtBuilderEntry, 1);
1634 entry->key = list->method;
1635 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1636 entry->has_target_code = 1;
1638 entry->children = entries->children + 1;
1639 entry->next = entries;
1643 mono_domain_unlock (domain);
1645 /* FIXME: Leaking memory ? */
1650 * mono_method_add_generic_virtual_invocation:
1652 * @vtable_slot: pointer to the vtable slot
1653 * @method: the inflated generic virtual method
1654 * @code: the method's code
1656 * Registers a call via unmanaged code to a generic virtual method
1657 * instantiation or variant interface method. If the number of calls reaches a threshold
1658 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1659 * virtual method trampoline.
1662 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1663 gpointer *vtable_slot,
1664 MonoMethod *method, gpointer code)
1666 MONO_REQ_GC_NEUTRAL_MODE;
1668 static gboolean inited = FALSE;
1669 static int num_added = 0;
1670 static int num_freed = 0;
1672 GenericVirtualCase *gvc, *list;
1673 MonoImtBuilderEntry *entries;
1677 mono_domain_lock (domain);
1678 if (!domain->generic_virtual_cases)
1679 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1682 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1683 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1687 /* Check whether the case was already added */
1688 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1691 if (gvc->method == method)
1696 /* If not found, make a new one */
1698 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1699 gvc->method = method;
1702 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1704 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1709 if (++gvc->count == THUNK_THRESHOLD) {
1710 gpointer *old_thunk = (void **)*vtable_slot;
1711 gpointer vtable_trampoline = NULL;
1712 gpointer imt_trampoline = NULL;
1714 if ((gpointer)vtable_slot < (gpointer)vtable) {
1715 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1716 int imt_slot = MONO_IMT_SIZE + displacement;
1718 /* Force the rebuild of the trampoline at the next call */
1719 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1720 *vtable_slot = imt_trampoline;
1722 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1724 entries = get_generic_virtual_entries (domain, vtable_slot);
1726 sorted = imt_sort_slot_entries (entries);
1728 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1732 MonoImtBuilderEntry *next = entries->next;
1737 for (i = 0; i < sorted->len; ++i)
1738 g_free (g_ptr_array_index (sorted, i));
1739 g_ptr_array_free (sorted, TRUE);
1741 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1746 mono_domain_unlock (domain);
1749 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1752 * mono_class_vtable:
1753 * @domain: the application domain
1754 * @class: the class to initialize
1756 * VTables are domain specific because we create domain specific code, and
1757 * they contain the domain specific static class data.
1758 * On failure, NULL is returned, and class->exception_type is set.
1761 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1764 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1765 mono_error_cleanup (&error);
1770 * mono_class_vtable_full:
1771 * @domain: the application domain
1772 * @class: the class to initialize
1773 * @error set on failure.
1775 * VTables are domain specific because we create domain specific code, and
1776 * they contain the domain specific static class data.
1779 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1781 MONO_REQ_GC_UNSAFE_MODE;
1783 MonoClassRuntimeInfo *runtime_info;
1785 mono_error_init (error);
1789 if (mono_class_has_failure (klass)) {
1790 mono_error_set_for_class_failure (error, klass);
1794 /* this check can be inlined in jitted code, too */
1795 runtime_info = klass->runtime_info;
1796 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1797 return runtime_info->domain_vtables [domain->domain_id];
1798 return mono_class_create_runtime_vtable (domain, klass, error);
1802 * mono_class_try_get_vtable:
1803 * @domain: the application domain
1804 * @class: the class to initialize
1806 * This function tries to get the associated vtable from @class if
1807 * it was already created.
1810 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1812 MONO_REQ_GC_NEUTRAL_MODE;
1814 MonoClassRuntimeInfo *runtime_info;
1818 runtime_info = klass->runtime_info;
1819 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1820 return runtime_info->domain_vtables [domain->domain_id];
1825 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1827 MONO_REQ_GC_NEUTRAL_MODE;
1829 size_t alloc_offset;
1832 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1833 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1834 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1836 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1837 g_assert ((imt_table_bytes & 7) == 4);
1844 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1848 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1850 MONO_REQ_GC_UNSAFE_MODE;
1853 MonoClassRuntimeInfo *runtime_info, *old_info;
1854 MonoClassField *field;
1856 int i, vtable_slots;
1857 size_t imt_table_bytes;
1859 guint32 vtable_size, class_size;
1861 gpointer *interface_offsets;
1863 mono_error_init (error);
1865 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1866 mono_domain_lock (domain);
1867 runtime_info = klass->runtime_info;
1868 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1869 mono_domain_unlock (domain);
1870 mono_loader_unlock ();
1871 return runtime_info->domain_vtables [domain->domain_id];
1873 if (!klass->inited || mono_class_has_failure (klass)) {
1874 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1875 mono_domain_unlock (domain);
1876 mono_loader_unlock ();
1877 mono_error_set_for_class_failure (error, klass);
1882 /* Array types require that their element type be valid*/
1883 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1884 MonoClass *element_class = klass->element_class;
1885 if (!element_class->inited)
1886 mono_class_init (element_class);
1888 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1889 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1890 mono_class_setup_vtable (element_class);
1892 if (mono_class_has_failure (element_class)) {
1893 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1894 if (!mono_class_has_failure (klass))
1895 mono_class_set_type_load_failure (klass, "");
1896 mono_domain_unlock (domain);
1897 mono_loader_unlock ();
1898 mono_error_set_for_class_failure (error, klass);
1904 * For some classes, mono_class_init () already computed klass->vtable_size, and
1905 * that is all that is needed because of the vtable trampolines.
1907 if (!klass->vtable_size)
1908 mono_class_setup_vtable (klass);
1910 if (mono_class_is_ginst (klass) && !klass->vtable)
1911 mono_class_check_vtable_constraints (klass, NULL);
1913 /* Initialize klass->has_finalize */
1914 mono_class_has_finalizer (klass);
1916 if (mono_class_has_failure (klass)) {
1917 mono_domain_unlock (domain);
1918 mono_loader_unlock ();
1919 mono_error_set_for_class_failure (error, klass);
1923 vtable_slots = klass->vtable_size;
1924 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1925 class_size = mono_class_data_size (klass);
1929 if (klass->interface_offsets_count) {
1930 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1931 mono_stats.imt_number_of_tables++;
1932 mono_stats.imt_tables_size += imt_table_bytes;
1934 imt_table_bytes = 0;
1937 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1939 mono_stats.used_class_count++;
1940 mono_stats.class_vtable_size += vtable_size;
1942 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1943 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1944 g_assert (!((gsize)vt & 7));
1947 vt->rank = klass->rank;
1948 vt->domain = domain;
1950 mono_class_compute_gc_descriptor (klass);
1952 * We can't use typed allocation in the non-root domains, since the
1953 * collector needs the GC descriptor stored in the vtable even after
1954 * the mempool containing the vtable is destroyed when the domain is
1955 * unloaded. An alternative might be to allocate vtables in the GC
1956 * heap, but this does not seem to work (it leads to crashes inside
1957 * libgc). If that approach is tried, two gc descriptors need to be
1958 * allocated for each class: one for the root domain, and one for all
1959 * other domains. The second descriptor should contain a bit for the
1960 * vtable field in MonoObject, since we can no longer assume the
1961 * vtable is reachable by other roots after the appdomain is unloaded.
1963 #ifdef HAVE_BOEHM_GC
1964 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1965 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1968 vt->gc_descr = klass->gc_descr;
1970 gc_bits = mono_gc_get_vtable_bits (klass);
1971 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1973 vt->gc_bits = gc_bits;
1976 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1977 if (klass->has_static_refs) {
1978 MonoGCDescriptor statics_gc_descr;
1980 gsize default_bitmap [4] = {0};
1983 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1984 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1985 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1986 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1987 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1988 if (bitmap != default_bitmap)
1991 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1993 vt->has_static_fields = TRUE;
1994 mono_stats.class_static_data_size += class_size;
1998 while ((field = mono_class_get_fields (klass, &iter))) {
1999 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2001 if (mono_field_is_deleted (field))
2003 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2004 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2005 if (special_static != SPECIAL_STATIC_NONE) {
2006 guint32 size, offset;
2008 gsize default_bitmap [4] = {0};
2013 if (mono_type_is_reference (field->type)) {
2014 default_bitmap [0] = 1;
2016 bitmap = default_bitmap;
2017 } else if (mono_type_is_struct (field->type)) {
2018 fclass = mono_class_from_mono_type (field->type);
2019 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2020 numbits = max_set + 1;
2022 default_bitmap [0] = 0;
2024 bitmap = default_bitmap;
2026 size = mono_type_size (field->type, &align);
2027 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2028 if (!domain->special_static_fields)
2029 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2030 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2031 if (bitmap != default_bitmap)
2034 * This marks the field as special static to speed up the
2035 * checks in mono_field_static_get/set_value ().
2041 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2042 MonoClass *fklass = mono_class_from_mono_type (field->type);
2043 const char *data = mono_field_get_data (field);
2045 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2046 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2047 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2050 if (fklass->valuetype) {
2051 memcpy (t, data, mono_class_value_size (fklass, NULL));
2053 /* it's a pointer type: add check */
2054 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2061 vt->max_interface_id = klass->max_interface_id;
2062 vt->interface_bitmap = klass->interface_bitmap;
2064 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2065 // class->name, klass->interface_offsets_count);
2067 /* Initialize vtable */
2068 if (callbacks.get_vtable_trampoline) {
2069 // This also covers the AOT case
2070 for (i = 0; i < klass->vtable_size; ++i) {
2071 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2074 mono_class_setup_vtable (klass);
2076 for (i = 0; i < klass->vtable_size; ++i) {
2079 cm = klass->vtable [i];
2081 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2082 if (!is_ok (error)) {
2083 mono_domain_unlock (domain);
2084 mono_loader_unlock ();
2091 if (imt_table_bytes) {
2092 /* Now that the vtable is full, we can actually fill up the IMT */
2093 for (i = 0; i < MONO_IMT_SIZE; ++i)
2094 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2098 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2099 * re-acquire them and check if another thread has created the vtable in the meantime.
2101 /* Special case System.MonoType to avoid infinite recursion */
2102 if (klass != mono_defaults.runtimetype_class) {
2103 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2104 if (!is_ok (error)) {
2105 mono_domain_unlock (domain);
2106 mono_loader_unlock ();
2110 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2111 /* This is unregistered in
2112 unregister_vtable_reflection_type() in
2114 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2117 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2119 /* class_vtable_array keeps an array of created vtables
2121 g_ptr_array_add (domain->class_vtable_array, vt);
2122 /* klass->runtime_info is protected by the loader lock, both when
2123 * it it enlarged and when it is stored info.
2127 * Store the vtable in klass->runtime_info.
2128 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2130 mono_memory_barrier ();
2132 old_info = klass->runtime_info;
2133 if (old_info && old_info->max_domain >= domain->domain_id) {
2134 /* someone already created a large enough runtime info */
2135 old_info->domain_vtables [domain->domain_id] = vt;
2137 int new_size = domain->domain_id;
2139 new_size = MAX (new_size, old_info->max_domain);
2141 /* make the new size a power of two */
2143 while (new_size > i)
2146 /* this is a bounded memory retention issue: may want to
2147 * handle it differently when we'll have a rcu-like system.
2149 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2150 runtime_info->max_domain = new_size - 1;
2151 /* copy the stuff from the older info */
2153 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2155 runtime_info->domain_vtables [domain->domain_id] = vt;
2157 mono_memory_barrier ();
2158 klass->runtime_info = runtime_info;
2161 if (klass == mono_defaults.runtimetype_class) {
2162 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2163 if (!is_ok (error)) {
2164 mono_domain_unlock (domain);
2165 mono_loader_unlock ();
2169 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2170 /* This is unregistered in
2171 unregister_vtable_reflection_type() in
2173 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2176 mono_domain_unlock (domain);
2177 mono_loader_unlock ();
2179 /* make sure the parent is initialized */
2180 /*FIXME shouldn't this fail the current type?*/
2182 mono_class_vtable_full (domain, klass->parent, error);
2187 #ifndef DISABLE_REMOTING
2189 * mono_class_proxy_vtable:
2190 * @domain: the application domain
2191 * @remove_class: the remote class
2192 * @error: set on error
2194 * Creates a vtable for transparent proxies. It is basically
2195 * a copy of the real vtable of the class wrapped in @remote_class,
2196 * but all function pointers invoke the remoting functions, and
2197 * vtable->klass points to the transparent proxy class, and not to @class.
2199 * On failure returns NULL and sets @error
2202 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2204 MONO_REQ_GC_UNSAFE_MODE;
2206 MonoVTable *vt, *pvt;
2207 int i, j, vtsize, extra_interface_vtsize = 0;
2208 guint32 max_interface_id;
2210 GSList *extra_interfaces = NULL;
2211 MonoClass *klass = remote_class->proxy_class;
2212 gpointer *interface_offsets;
2213 uint8_t *bitmap = NULL;
2215 size_t imt_table_bytes;
2217 #ifdef COMPRESSED_INTERFACE_BITMAP
2221 mono_error_init (error);
2223 vt = mono_class_vtable (domain, klass);
2224 g_assert (vt); /*FIXME property handle failure*/
2225 max_interface_id = vt->max_interface_id;
2227 /* Calculate vtable space for extra interfaces */
2228 for (j = 0; j < remote_class->interface_count; j++) {
2229 MonoClass* iclass = remote_class->interfaces[j];
2233 /*FIXME test for interfaces with variant generic arguments*/
2234 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2235 continue; /* interface implemented by the class */
2236 if (g_slist_find (extra_interfaces, iclass))
2239 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2241 method_count = mono_class_num_methods (iclass);
2243 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2247 for (i = 0; i < ifaces->len; ++i) {
2248 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2249 /*FIXME test for interfaces with variant generic arguments*/
2250 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2251 continue; /* interface implemented by the class */
2252 if (g_slist_find (extra_interfaces, ic))
2254 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2255 method_count += mono_class_num_methods (ic);
2257 g_ptr_array_free (ifaces, TRUE);
2261 extra_interface_vtsize += method_count * sizeof (gpointer);
2262 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2265 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2266 mono_stats.imt_number_of_tables++;
2267 mono_stats.imt_tables_size += imt_table_bytes;
2269 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2271 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2273 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2274 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2275 g_assert (!((gsize)pvt & 7));
2277 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2279 pvt->klass = mono_defaults.transparent_proxy_class;
2280 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2281 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2283 /* initialize vtable */
2284 mono_class_setup_vtable (klass);
2285 for (i = 0; i < klass->vtable_size; ++i) {
2288 if ((cm = klass->vtable [i])) {
2289 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2293 pvt->vtable [i] = NULL;
2296 if (mono_class_is_abstract (klass)) {
2297 /* create trampolines for abstract methods */
2298 for (k = klass; k; k = k->parent) {
2300 gpointer iter = NULL;
2301 while ((m = mono_class_get_methods (k, &iter)))
2302 if (!pvt->vtable [m->slot]) {
2303 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2310 pvt->max_interface_id = max_interface_id;
2311 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2312 #ifdef COMPRESSED_INTERFACE_BITMAP
2313 bitmap = (uint8_t *)g_malloc0 (bsize);
2315 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2318 for (i = 0; i < klass->interface_offsets_count; ++i) {
2319 int interface_id = klass->interfaces_packed [i]->interface_id;
2320 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2323 if (extra_interfaces) {
2324 int slot = klass->vtable_size;
2330 /* Create trampolines for the methods of the interfaces */
2331 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2332 interf = (MonoClass *)list_item->data;
2334 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2338 while ((cm = mono_class_get_methods (interf, &iter))) {
2339 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2344 slot += mono_class_num_methods (interf);
2348 /* Now that the vtable is full, we can actually fill up the IMT */
2349 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2350 if (extra_interfaces) {
2351 g_slist_free (extra_interfaces);
2354 #ifdef COMPRESSED_INTERFACE_BITMAP
2355 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2356 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2357 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2360 pvt->interface_bitmap = bitmap;
2364 if (extra_interfaces)
2365 g_slist_free (extra_interfaces);
2366 #ifdef COMPRESSED_INTERFACE_BITMAP
2372 #endif /* DISABLE_REMOTING */
2375 * mono_class_field_is_special_static:
2377 * Returns whether @field is a thread/context static field.
2380 mono_class_field_is_special_static (MonoClassField *field)
2382 MONO_REQ_GC_NEUTRAL_MODE
2384 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2386 if (mono_field_is_deleted (field))
2388 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2389 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2396 * mono_class_field_get_special_static_type:
2397 * @field: The MonoClassField describing the field.
2399 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2400 * SPECIAL_STATIC_NONE otherwise.
2403 mono_class_field_get_special_static_type (MonoClassField *field)
2405 MONO_REQ_GC_NEUTRAL_MODE
2407 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2408 return SPECIAL_STATIC_NONE;
2409 if (mono_field_is_deleted (field))
2410 return SPECIAL_STATIC_NONE;
2411 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2412 return field_is_special_static (field->parent, field);
2413 return SPECIAL_STATIC_NONE;
2417 * mono_class_has_special_static_fields:
2419 * Returns whenever @klass has any thread/context static fields.
2422 mono_class_has_special_static_fields (MonoClass *klass)
2424 MONO_REQ_GC_NEUTRAL_MODE
2426 MonoClassField *field;
2430 while ((field = mono_class_get_fields (klass, &iter))) {
2431 g_assert (field->parent == klass);
2432 if (mono_class_field_is_special_static (field))
2439 #ifndef DISABLE_REMOTING
2441 * create_remote_class_key:
2442 * Creates an array of pointers that can be used as a hash key for a remote class.
2443 * The first element of the array is the number of pointers.
2446 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2448 MONO_REQ_GC_NEUTRAL_MODE;
2453 if (remote_class == NULL) {
2454 if (mono_class_is_interface (extra_class)) {
2455 key = (void **)g_malloc (sizeof(gpointer) * 3);
2456 key [0] = GINT_TO_POINTER (2);
2457 key [1] = mono_defaults.marshalbyrefobject_class;
2458 key [2] = extra_class;
2460 key = (void **)g_malloc (sizeof(gpointer) * 2);
2461 key [0] = GINT_TO_POINTER (1);
2462 key [1] = extra_class;
2465 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2466 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2467 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2468 key [1] = remote_class->proxy_class;
2470 // Keep the list of interfaces sorted
2471 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2472 if (extra_class && remote_class->interfaces [i] > extra_class) {
2473 key [j++] = extra_class;
2476 key [j] = remote_class->interfaces [i];
2479 key [j] = extra_class;
2481 // Replace the old class. The interface list is the same
2482 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2483 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2484 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2485 for (i = 0; i < remote_class->interface_count; i++)
2486 key [2 + i] = remote_class->interfaces [i];
2494 * copy_remote_class_key:
2496 * Make a copy of KEY in the domain and return the copy.
2499 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2501 MONO_REQ_GC_NEUTRAL_MODE
2503 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2504 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2506 memcpy (mp_key, key, key_size);
2512 * mono_remote_class:
2513 * @domain: the application domain
2514 * @class_name: name of the remote class
2515 * @error: set on error
2517 * Creates and initializes a MonoRemoteClass object for a remote type.
2519 * On failure returns NULL and sets @error
2522 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2524 MONO_REQ_GC_UNSAFE_MODE;
2526 MonoRemoteClass *rc;
2527 gpointer* key, *mp_key;
2530 mono_error_init (error);
2532 key = create_remote_class_key (NULL, proxy_class);
2534 mono_domain_lock (domain);
2535 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2539 mono_domain_unlock (domain);
2543 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2544 if (!is_ok (error)) {
2546 mono_domain_unlock (domain);
2550 mp_key = copy_remote_class_key (domain, key);
2554 if (mono_class_is_interface (proxy_class)) {
2555 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2556 rc->interface_count = 1;
2557 rc->interfaces [0] = proxy_class;
2558 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2560 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2561 rc->interface_count = 0;
2562 rc->proxy_class = proxy_class;
2565 rc->default_vtable = NULL;
2566 rc->xdomain_vtable = NULL;
2567 rc->proxy_class_name = name;
2568 #ifndef DISABLE_PERFCOUNTERS
2569 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2572 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2574 mono_domain_unlock (domain);
2579 * clone_remote_class:
2580 * Creates a copy of the remote_class, adding the provided class or interface
2582 static MonoRemoteClass*
2583 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2585 MONO_REQ_GC_NEUTRAL_MODE;
2587 MonoRemoteClass *rc;
2588 gpointer* key, *mp_key;
2590 key = create_remote_class_key (remote_class, extra_class);
2591 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2597 mp_key = copy_remote_class_key (domain, key);
2601 if (mono_class_is_interface (extra_class)) {
2603 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2604 rc->proxy_class = remote_class->proxy_class;
2605 rc->interface_count = remote_class->interface_count + 1;
2607 // Keep the list of interfaces sorted, since the hash key of
2608 // the remote class depends on this
2609 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2610 if (remote_class->interfaces [i] > extra_class && i == j)
2611 rc->interfaces [j++] = extra_class;
2612 rc->interfaces [j] = remote_class->interfaces [i];
2615 rc->interfaces [j] = extra_class;
2617 // Replace the old class. The interface array is the same
2618 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2619 rc->proxy_class = extra_class;
2620 rc->interface_count = remote_class->interface_count;
2621 if (rc->interface_count > 0)
2622 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2625 rc->default_vtable = NULL;
2626 rc->xdomain_vtable = NULL;
2627 rc->proxy_class_name = remote_class->proxy_class_name;
2629 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2635 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2637 MONO_REQ_GC_UNSAFE_MODE;
2639 mono_error_init (error);
2641 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2642 mono_domain_lock (domain);
2643 if (rp->target_domain_id != -1) {
2644 if (remote_class->xdomain_vtable == NULL)
2645 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2646 mono_domain_unlock (domain);
2647 mono_loader_unlock ();
2648 return_val_if_nok (error, NULL);
2649 return remote_class->xdomain_vtable;
2651 if (remote_class->default_vtable == NULL) {
2654 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2655 klass = mono_class_from_mono_type (type);
2657 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)))
2658 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2661 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2662 /* N.B. both branches of the if modify error */
2663 if (!is_ok (error)) {
2664 mono_domain_unlock (domain);
2665 mono_loader_unlock ();
2670 mono_domain_unlock (domain);
2671 mono_loader_unlock ();
2672 return remote_class->default_vtable;
2676 * mono_upgrade_remote_class:
2677 * @domain: the application domain
2678 * @tproxy: the proxy whose remote class has to be upgraded.
2679 * @klass: class to which the remote class can be casted.
2680 * @error: set on error
2682 * Updates the vtable of the remote class by adding the necessary method slots
2683 * and interface offsets so it can be safely casted to klass. klass can be a
2684 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2687 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2689 MONO_REQ_GC_UNSAFE_MODE;
2691 MonoTransparentProxy *tproxy;
2692 MonoRemoteClass *remote_class;
2693 gboolean redo_vtable;
2695 mono_error_init (error);
2696 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2697 mono_domain_lock (domain);
2699 tproxy = (MonoTransparentProxy*) proxy_object;
2700 remote_class = tproxy->remote_class;
2702 if (mono_class_is_interface (klass)) {
2705 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2706 if (remote_class->interfaces [i] == klass)
2707 redo_vtable = FALSE;
2710 redo_vtable = (remote_class->proxy_class != klass);
2714 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2715 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2721 mono_domain_unlock (domain);
2722 mono_loader_unlock ();
2723 return is_ok (error);
2725 #endif /* DISABLE_REMOTING */
2729 * mono_object_get_virtual_method:
2730 * @obj: object to operate on.
2733 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2734 * the instance of a callvirt of method.
2737 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2739 MONO_REQ_GC_UNSAFE_MODE;
2742 MonoMethod **vtable;
2743 gboolean is_proxy = FALSE;
2744 MonoMethod *res = NULL;
2746 klass = mono_object_class (obj);
2747 #ifndef DISABLE_REMOTING
2748 if (klass == mono_defaults.transparent_proxy_class) {
2749 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2754 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2757 mono_class_setup_vtable (klass);
2758 vtable = klass->vtable;
2760 if (method->slot == -1) {
2761 /* method->slot might not be set for instances of generic methods */
2762 if (method->is_inflated) {
2763 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2764 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2767 g_assert_not_reached ();
2771 /* check method->slot is a valid index: perform isinstance? */
2772 if (method->slot != -1) {
2773 if (mono_class_is_interface (method->klass)) {
2775 gboolean variance_used = FALSE;
2776 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2777 g_assert (iface_offset > 0);
2778 res = vtable [iface_offset + method->slot];
2781 res = vtable [method->slot];
2785 #ifndef DISABLE_REMOTING
2787 /* It may be an interface, abstract class method or generic method */
2788 if (!res || mono_method_signature (res)->generic_param_count)
2791 /* generic methods demand invoke_with_check */
2792 if (mono_method_signature (res)->generic_param_count)
2793 res = mono_marshal_get_remoting_invoke_with_check (res);
2796 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2797 res = mono_cominterop_get_invoke (res);
2800 res = mono_marshal_get_remoting_invoke (res);
2805 if (method->is_inflated) {
2807 /* Have to inflate the result */
2808 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2809 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2819 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2821 MONO_REQ_GC_UNSAFE_MODE;
2823 MonoObject *result = NULL;
2825 g_assert (callbacks.runtime_invoke);
2827 mono_error_init (error);
2829 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2830 mono_profiler_method_start_invoke (method);
2832 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2834 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2835 mono_profiler_method_end_invoke (method);
2837 if (!mono_error_ok (error))
2844 * mono_runtime_invoke:
2845 * @method: method to invoke
2846 * @obJ: object instance
2847 * @params: arguments to the method
2848 * @exc: exception information.
2850 * Invokes the method represented by @method on the object @obj.
2852 * obj is the 'this' pointer, it should be NULL for static
2853 * methods, a MonoObject* for object instances and a pointer to
2854 * the value type for value types.
2856 * The params array contains the arguments to the method with the
2857 * same convention: MonoObject* pointers for object instances and
2858 * pointers to the value type otherwise.
2860 * From unmanaged code you'll usually use the
2861 * mono_runtime_invoke() variant.
2863 * Note that this function doesn't handle virtual methods for
2864 * you, it will exec the exact method you pass: we still need to
2865 * expose a function to lookup the derived class implementation
2866 * of a virtual method (there are examples of this in the code,
2869 * You can pass NULL as the exc argument if you don't want to
2870 * catch exceptions, otherwise, *exc will be set to the exception
2871 * thrown, if any. if an exception is thrown, you can't use the
2872 * MonoObject* result from the function.
2874 * If the method returns a value type, it is boxed in an object
2878 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2883 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2884 if (*exc == NULL && !mono_error_ok(&error)) {
2885 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2887 mono_error_cleanup (&error);
2889 res = mono_runtime_invoke_checked (method, obj, params, &error);
2890 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2896 * mono_runtime_try_invoke:
2897 * @method: method to invoke
2898 * @obJ: object instance
2899 * @params: arguments to the method
2900 * @exc: exception information.
2901 * @error: set on error
2903 * Invokes the method represented by @method on the object @obj.
2905 * obj is the 'this' pointer, it should be NULL for static
2906 * methods, a MonoObject* for object instances and a pointer to
2907 * the value type for value types.
2909 * The params array contains the arguments to the method with the
2910 * same convention: MonoObject* pointers for object instances and
2911 * pointers to the value type otherwise.
2913 * From unmanaged code you'll usually use the
2914 * mono_runtime_invoke() variant.
2916 * Note that this function doesn't handle virtual methods for
2917 * you, it will exec the exact method you pass: we still need to
2918 * expose a function to lookup the derived class implementation
2919 * of a virtual method (there are examples of this in the code,
2922 * For this function, you must not pass NULL as the exc argument if
2923 * you don't want to catch exceptions, use
2924 * mono_runtime_invoke_checked(). If an exception is thrown, you
2925 * can't use the MonoObject* result from the function.
2927 * If this method cannot be invoked, @error will be set and @exc and
2928 * the return value must not be used.
2930 * If the method returns a value type, it is boxed in an object
2934 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2936 MONO_REQ_GC_UNSAFE_MODE;
2938 g_assert (exc != NULL);
2940 if (mono_runtime_get_no_exec ())
2941 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2943 return do_runtime_invoke (method, obj, params, exc, error);
2947 * mono_runtime_invoke_checked:
2948 * @method: method to invoke
2949 * @obJ: object instance
2950 * @params: arguments to the method
2951 * @error: set on error
2953 * Invokes the method represented by @method on the object @obj.
2955 * obj is the 'this' pointer, it should be NULL for static
2956 * methods, a MonoObject* for object instances and a pointer to
2957 * the value type for value types.
2959 * The params array contains the arguments to the method with the
2960 * same convention: MonoObject* pointers for object instances and
2961 * pointers to the value type otherwise.
2963 * From unmanaged code you'll usually use the
2964 * mono_runtime_invoke() variant.
2966 * Note that this function doesn't handle virtual methods for
2967 * you, it will exec the exact method you pass: we still need to
2968 * expose a function to lookup the derived class implementation
2969 * of a virtual method (there are examples of this in the code,
2972 * If an exception is thrown, you can't use the MonoObject* result
2973 * from the function.
2975 * If this method cannot be invoked, @error will be set. If the
2976 * method throws an exception (and we're in coop mode) the exception
2977 * will be set in @error.
2979 * If the method returns a value type, it is boxed in an object
2983 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2985 MONO_REQ_GC_UNSAFE_MODE;
2987 if (mono_runtime_get_no_exec ())
2988 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2990 return do_runtime_invoke (method, obj, params, NULL, error);
2994 * mono_method_get_unmanaged_thunk:
2995 * @method: method to generate a thunk for.
2997 * Returns an unmanaged->managed thunk that can be used to call
2998 * a managed method directly from C.
3000 * The thunk's C signature closely matches the managed signature:
3002 * C#: public bool Equals (object obj);
3003 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3004 * MonoObject*, MonoException**);
3006 * The 1st ("this") parameter must not be used with static methods:
3008 * C#: public static bool ReferenceEquals (object a, object b);
3009 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3012 * The last argument must be a non-null pointer of a MonoException* pointer.
3013 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3014 * exception has been thrown in managed code. Otherwise it will point
3015 * to the MonoException* caught by the thunk. In this case, the result of
3016 * the thunk is undefined:
3018 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3019 * MonoException *ex = NULL;
3020 * Equals func = mono_method_get_unmanaged_thunk (method);
3021 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3023 * // handle exception
3026 * The calling convention of the thunk matches the platform's default
3027 * convention. This means that under Windows, C declarations must
3028 * contain the __stdcall attribute:
3030 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3031 * MonoObject*, MonoException**);
3035 * Value type arguments and return values are treated as they were objects:
3037 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3038 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3040 * Arguments must be properly boxed upon trunk's invocation, while return
3041 * values must be unboxed.
3044 mono_method_get_unmanaged_thunk (MonoMethod *method)
3046 MONO_REQ_GC_NEUTRAL_MODE;
3047 MONO_REQ_API_ENTRYPOINT;
3052 g_assert (!mono_threads_is_coop_enabled ());
3054 MONO_ENTER_GC_UNSAFE;
3055 method = mono_marshal_get_thunk_invoke_wrapper (method);
3056 res = mono_compile_method_checked (method, &error);
3057 mono_error_cleanup (&error);
3058 MONO_EXIT_GC_UNSAFE;
3064 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3066 MONO_REQ_GC_UNSAFE_MODE;
3070 /* object fields cannot be byref, so we don't need a
3072 gpointer *p = (gpointer*)dest;
3079 case MONO_TYPE_BOOLEAN:
3081 case MONO_TYPE_U1: {
3082 guint8 *p = (guint8*)dest;
3083 *p = value ? *(guint8*)value : 0;
3088 case MONO_TYPE_CHAR: {
3089 guint16 *p = (guint16*)dest;
3090 *p = value ? *(guint16*)value : 0;
3093 #if SIZEOF_VOID_P == 4
3098 case MONO_TYPE_U4: {
3099 gint32 *p = (gint32*)dest;
3100 *p = value ? *(gint32*)value : 0;
3103 #if SIZEOF_VOID_P == 8
3108 case MONO_TYPE_U8: {
3109 gint64 *p = (gint64*)dest;
3110 *p = value ? *(gint64*)value : 0;
3113 case MONO_TYPE_R4: {
3114 float *p = (float*)dest;
3115 *p = value ? *(float*)value : 0;
3118 case MONO_TYPE_R8: {
3119 double *p = (double*)dest;
3120 *p = value ? *(double*)value : 0;
3123 case MONO_TYPE_STRING:
3124 case MONO_TYPE_SZARRAY:
3125 case MONO_TYPE_CLASS:
3126 case MONO_TYPE_OBJECT:
3127 case MONO_TYPE_ARRAY:
3128 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3130 case MONO_TYPE_FNPTR:
3131 case MONO_TYPE_PTR: {
3132 gpointer *p = (gpointer*)dest;
3133 *p = deref_pointer? *(gpointer*)value: value;
3136 case MONO_TYPE_VALUETYPE:
3137 /* note that 't' and 'type->type' can be different */
3138 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3139 t = mono_class_enum_basetype (type->data.klass)->type;
3142 MonoClass *klass = mono_class_from_mono_type (type);
3143 int size = mono_class_value_size (klass, NULL);
3145 mono_gc_bzero_atomic (dest, size);
3147 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3150 case MONO_TYPE_GENERICINST:
3151 t = type->data.generic_class->container_class->byval_arg.type;
3154 g_error ("got type %x", type->type);
3159 * mono_field_set_value:
3160 * @obj: Instance object
3161 * @field: MonoClassField describing the field to set
3162 * @value: The value to be set
3164 * Sets the value of the field described by @field in the object instance @obj
3165 * to the value passed in @value. This method should only be used for instance
3166 * fields. For static fields, use mono_field_static_set_value.
3168 * The value must be on the native format of the field type.
3171 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3173 MONO_REQ_GC_UNSAFE_MODE;
3177 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3179 dest = (char*)obj + field->offset;
3180 mono_copy_value (field->type, dest, value, FALSE);
3184 * mono_field_static_set_value:
3185 * @field: MonoClassField describing the field to set
3186 * @value: The value to be set
3188 * Sets the value of the static field described by @field
3189 * to the value passed in @value.
3191 * The value must be on the native format of the field type.
3194 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3196 MONO_REQ_GC_UNSAFE_MODE;
3200 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3201 /* you cant set a constant! */
3202 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3204 if (field->offset == -1) {
3205 /* Special static */
3208 mono_domain_lock (vt->domain);
3209 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3210 mono_domain_unlock (vt->domain);
3211 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3213 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3215 mono_copy_value (field->type, dest, value, FALSE);
3219 * mono_vtable_get_static_field_data:
3221 * Internal use function: return a pointer to the memory holding the static fields
3222 * for a class or NULL if there are no static fields.
3223 * This is exported only for use by the debugger.
3226 mono_vtable_get_static_field_data (MonoVTable *vt)
3228 MONO_REQ_GC_NEUTRAL_MODE
3230 if (!vt->has_static_fields)
3232 return vt->vtable [vt->klass->vtable_size];
3236 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3238 MONO_REQ_GC_UNSAFE_MODE;
3242 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3243 if (field->offset == -1) {
3244 /* Special static */
3247 mono_domain_lock (vt->domain);
3248 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3249 mono_domain_unlock (vt->domain);
3250 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3252 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3255 src = (guint8*)obj + field->offset;
3262 * mono_field_get_value:
3263 * @obj: Object instance
3264 * @field: MonoClassField describing the field to fetch information from
3265 * @value: pointer to the location where the value will be stored
3267 * Use this routine to get the value of the field @field in the object
3270 * The pointer provided by value must be of the field type, for reference
3271 * types this is a MonoObject*, for value types its the actual pointer to
3276 * mono_field_get_value (obj, int_field, &i);
3279 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3281 MONO_REQ_GC_UNSAFE_MODE;
3287 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3289 src = (char*)obj + field->offset;
3290 mono_copy_value (field->type, value, src, TRUE);
3294 * mono_field_get_value_object:
3295 * @domain: domain where the object will be created (if boxing)
3296 * @field: MonoClassField describing the field to fetch information from
3297 * @obj: The object instance for the field.
3299 * Returns: a new MonoObject with the value from the given field. If the
3300 * field represents a value type, the value is boxed.
3304 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3307 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3308 mono_error_assert_ok (&error);
3313 * mono_field_get_value_object_checked:
3314 * @domain: domain where the object will be created (if boxing)
3315 * @field: MonoClassField describing the field to fetch information from
3316 * @obj: The object instance for the field.
3317 * @error: Set on error.
3319 * Returns: a new MonoObject with the value from the given field. If the
3320 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3324 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3326 MONO_REQ_GC_UNSAFE_MODE;
3328 mono_error_init (error);
3332 MonoVTable *vtable = NULL;
3334 gboolean is_static = FALSE;
3335 gboolean is_ref = FALSE;
3336 gboolean is_literal = FALSE;
3337 gboolean is_ptr = FALSE;
3338 MonoType *type = mono_field_get_type_checked (field, error);
3340 return_val_if_nok (error, NULL);
3342 switch (type->type) {
3343 case MONO_TYPE_STRING:
3344 case MONO_TYPE_OBJECT:
3345 case MONO_TYPE_CLASS:
3346 case MONO_TYPE_ARRAY:
3347 case MONO_TYPE_SZARRAY:
3352 case MONO_TYPE_BOOLEAN:
3355 case MONO_TYPE_CHAR:
3364 case MONO_TYPE_VALUETYPE:
3365 is_ref = type->byref;
3367 case MONO_TYPE_GENERICINST:
3368 is_ref = !mono_type_generic_inst_is_valuetype (type);
3374 g_error ("type 0x%x not handled in "
3375 "mono_field_get_value_object", type->type);
3379 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3382 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3386 vtable = mono_class_vtable_full (domain, field->parent, error);
3387 return_val_if_nok (error, NULL);
3389 if (!vtable->initialized) {
3390 mono_runtime_class_init_full (vtable, error);
3391 return_val_if_nok (error, NULL);
3400 get_default_field_value (domain, field, &o, error);
3401 return_val_if_nok (error, NULL);
3402 } else if (is_static) {
3403 mono_field_static_get_value_checked (vtable, field, &o, error);
3404 return_val_if_nok (error, NULL);
3406 mono_field_get_value (obj, field, &o);
3412 static MonoMethod *m;
3418 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3419 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3425 get_default_field_value (domain, field, v, error);
3426 return_val_if_nok (error, NULL);
3427 } else if (is_static) {
3428 mono_field_static_get_value_checked (vtable, field, v, error);
3429 return_val_if_nok (error, NULL);
3431 mono_field_get_value (obj, field, v);
3434 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3435 args [0] = ptr ? *ptr : NULL;
3436 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3437 return_val_if_nok (error, NULL);
3439 o = mono_runtime_invoke_checked (m, NULL, args, error);
3440 return_val_if_nok (error, NULL);
3445 /* boxed value type */
3446 klass = mono_class_from_mono_type (type);
3448 if (mono_class_is_nullable (klass))
3449 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3451 o = mono_object_new_checked (domain, klass, error);
3452 return_val_if_nok (error, NULL);
3453 v = ((gchar *) o) + sizeof (MonoObject);
3456 get_default_field_value (domain, field, v, error);
3457 return_val_if_nok (error, NULL);
3458 } else if (is_static) {
3459 mono_field_static_get_value_checked (vtable, field, v, error);
3460 return_val_if_nok (error, NULL);
3462 mono_field_get_value (obj, field, v);
3469 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3471 MONO_REQ_GC_UNSAFE_MODE;
3473 mono_error_init (error);
3475 const char *p = blob;
3476 mono_metadata_decode_blob_size (p, &p);
3479 case MONO_TYPE_BOOLEAN:
3482 *(guint8 *) value = *p;
3484 case MONO_TYPE_CHAR:
3487 *(guint16*) value = read16 (p);
3491 *(guint32*) value = read32 (p);
3495 *(guint64*) value = read64 (p);
3498 readr4 (p, (float*) value);
3501 readr8 (p, (double*) value);
3503 case MONO_TYPE_STRING:
3504 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3506 case MONO_TYPE_CLASS:
3507 *(gpointer*) value = NULL;
3511 g_warning ("type 0x%02x should not be in constant table", type);
3517 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3519 MONO_REQ_GC_NEUTRAL_MODE;
3521 MonoTypeEnum def_type;
3524 mono_error_init (error);
3526 data = mono_class_get_field_default_value (field, &def_type);
3527 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3531 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3533 MONO_REQ_GC_UNSAFE_MODE;
3537 mono_error_init (error);
3539 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3541 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3542 get_default_field_value (vt->domain, field, value, error);
3546 if (field->offset == -1) {
3547 /* Special static */
3548 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3549 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3551 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3553 mono_copy_value (field->type, value, src, TRUE);
3557 * mono_field_static_get_value:
3558 * @vt: vtable to the object
3559 * @field: MonoClassField describing the field to fetch information from
3560 * @value: where the value is returned
3562 * Use this routine to get the value of the static field @field value.
3564 * The pointer provided by value must be of the field type, for reference
3565 * types this is a MonoObject*, for value types its the actual pointer to
3570 * mono_field_static_get_value (vt, int_field, &i);
3573 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3575 MONO_REQ_GC_NEUTRAL_MODE;
3578 mono_field_static_get_value_checked (vt, field, value, &error);
3579 mono_error_cleanup (&error);
3583 * mono_field_static_get_value_checked:
3584 * @vt: vtable to the object
3585 * @field: MonoClassField describing the field to fetch information from
3586 * @value: where the value is returned
3587 * @error: set on error
3589 * Use this routine to get the value of the static field @field value.
3591 * The pointer provided by value must be of the field type, for reference
3592 * types this is a MonoObject*, for value types its the actual pointer to
3597 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3598 * if (!is_ok (error)) { ... }
3600 * On failure sets @error.
3603 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3605 MONO_REQ_GC_NEUTRAL_MODE;
3607 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3611 * mono_property_set_value:
3612 * @prop: MonoProperty to set
3613 * @obj: instance object on which to act
3614 * @params: parameters to pass to the propery
3615 * @exc: optional exception
3617 * Invokes the property's set method with the given arguments on the
3618 * object instance obj (or NULL for static properties).
3620 * You can pass NULL as the exc argument if you don't want to
3621 * catch exceptions, otherwise, *exc will be set to the exception
3622 * thrown, if any. if an exception is thrown, you can't use the
3623 * MonoObject* result from the function.
3626 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3628 MONO_REQ_GC_UNSAFE_MODE;
3631 do_runtime_invoke (prop->set, obj, params, exc, &error);
3632 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3633 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3635 mono_error_cleanup (&error);
3640 * mono_property_set_value_checked:
3641 * @prop: MonoProperty to set
3642 * @obj: instance object on which to act
3643 * @params: parameters to pass to the propery
3644 * @error: set on error
3646 * Invokes the property's set method with the given arguments on the
3647 * object instance obj (or NULL for static properties).
3649 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3650 * If an exception is thrown, it will be caught and returned via @error.
3653 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3655 MONO_REQ_GC_UNSAFE_MODE;
3659 mono_error_init (error);
3660 do_runtime_invoke (prop->set, obj, params, &exc, error);
3661 if (exc != NULL && is_ok (error))
3662 mono_error_set_exception_instance (error, (MonoException*)exc);
3663 return is_ok (error);
3667 * mono_property_get_value:
3668 * @prop: MonoProperty to fetch
3669 * @obj: instance object on which to act
3670 * @params: parameters to pass to the propery
3671 * @exc: optional exception
3673 * Invokes the property's get method with the given arguments on the
3674 * object instance obj (or NULL for static properties).
3676 * You can pass NULL as the exc argument if you don't want to
3677 * catch exceptions, otherwise, *exc will be set to the exception
3678 * thrown, if any. if an exception is thrown, you can't use the
3679 * MonoObject* result from the function.
3681 * Returns: the value from invoking the get method on the property.
3684 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3686 MONO_REQ_GC_UNSAFE_MODE;
3689 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3690 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3691 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3693 mono_error_cleanup (&error); /* FIXME don't raise here */
3700 * mono_property_get_value_checked:
3701 * @prop: MonoProperty to fetch
3702 * @obj: instance object on which to act
3703 * @params: parameters to pass to the propery
3704 * @error: set on error
3706 * Invokes the property's get method with the given arguments on the
3707 * object instance obj (or NULL for static properties).
3709 * If an exception is thrown, you can't use the
3710 * MonoObject* result from the function. The exception will be propagated via @error.
3712 * Returns: the value from invoking the get method on the property. On
3713 * failure returns NULL and sets @error.
3716 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3718 MONO_REQ_GC_UNSAFE_MODE;
3721 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3722 if (exc != NULL && !is_ok (error))
3723 mono_error_set_exception_instance (error, (MonoException*) exc);
3731 * mono_nullable_init:
3732 * @buf: The nullable structure to initialize.
3733 * @value: the value to initialize from
3734 * @klass: the type for the object
3736 * Initialize the nullable structure pointed to by @buf from @value which
3737 * should be a boxed value type. The size of @buf should be able to hold
3738 * as much data as the @klass->instance_size (which is the number of bytes
3739 * that will be copies).
3741 * Since Nullables have variable structure, we can not define a C
3742 * structure for them.
3745 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3747 MONO_REQ_GC_UNSAFE_MODE;
3749 MonoClass *param_class = klass->cast_class;
3751 mono_class_setup_fields (klass);
3752 g_assert (klass->fields_inited);
3754 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3755 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3757 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3759 if (param_class->has_references)
3760 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3762 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3764 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3769 * mono_nullable_box:
3770 * @buf: The buffer representing the data to be boxed
3771 * @klass: the type to box it as.
3772 * @error: set on oerr
3774 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3775 * @buf. On failure returns NULL and sets @error
3778 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3780 MONO_REQ_GC_UNSAFE_MODE;
3782 mono_error_init (error);
3783 MonoClass *param_class = klass->cast_class;
3785 mono_class_setup_fields (klass);
3786 g_assert (klass->fields_inited);
3788 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3789 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3791 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3792 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3793 return_val_if_nok (error, NULL);
3794 if (param_class->has_references)
3795 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3797 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3805 * mono_get_delegate_invoke:
3806 * @klass: The delegate class
3808 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3811 mono_get_delegate_invoke (MonoClass *klass)
3813 MONO_REQ_GC_NEUTRAL_MODE;
3817 /* This is called at runtime, so avoid the slower search in metadata */
3818 mono_class_setup_methods (klass);
3819 if (mono_class_has_failure (klass))
3821 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3826 * mono_get_delegate_begin_invoke:
3827 * @klass: The delegate class
3829 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3832 mono_get_delegate_begin_invoke (MonoClass *klass)
3834 MONO_REQ_GC_NEUTRAL_MODE;
3838 /* This is called at runtime, so avoid the slower search in metadata */
3839 mono_class_setup_methods (klass);
3840 if (mono_class_has_failure (klass))
3842 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3847 * mono_get_delegate_end_invoke:
3848 * @klass: The delegate class
3850 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3853 mono_get_delegate_end_invoke (MonoClass *klass)
3855 MONO_REQ_GC_NEUTRAL_MODE;
3859 /* This is called at runtime, so avoid the slower search in metadata */
3860 mono_class_setup_methods (klass);
3861 if (mono_class_has_failure (klass))
3863 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3868 * mono_runtime_delegate_invoke:
3869 * @delegate: pointer to a delegate object.
3870 * @params: parameters for the delegate.
3871 * @exc: Pointer to the exception result.
3873 * Invokes the delegate method @delegate with the parameters provided.
3875 * You can pass NULL as the exc argument if you don't want to
3876 * catch exceptions, otherwise, *exc will be set to the exception
3877 * thrown, if any. if an exception is thrown, you can't use the
3878 * MonoObject* result from the function.
3881 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3883 MONO_REQ_GC_UNSAFE_MODE;
3887 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3889 mono_error_cleanup (&error);
3892 if (!is_ok (&error))
3893 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3897 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3898 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3904 * mono_runtime_delegate_try_invoke:
3905 * @delegate: pointer to a delegate object.
3906 * @params: parameters for the delegate.
3907 * @exc: Pointer to the exception result.
3908 * @error: set on error
3910 * Invokes the delegate method @delegate with the parameters provided.
3912 * You can pass NULL as the exc argument if you don't want to
3913 * catch exceptions, otherwise, *exc will be set to the exception
3914 * thrown, if any. On failure to execute, @error will be set.
3915 * if an exception is thrown, you can't use the
3916 * MonoObject* result from the function.
3919 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3921 MONO_REQ_GC_UNSAFE_MODE;
3923 mono_error_init (error);
3925 MonoClass *klass = delegate->vtable->klass;
3928 im = mono_get_delegate_invoke (klass);
3930 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3933 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3935 o = mono_runtime_invoke_checked (im, delegate, params, error);
3942 * mono_runtime_delegate_invoke_checked:
3943 * @delegate: pointer to a delegate object.
3944 * @params: parameters for the delegate.
3945 * @error: set on error
3947 * Invokes the delegate method @delegate with the parameters provided.
3949 * On failure @error will be set and you can't use the MonoObject*
3950 * result from the function.
3953 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3955 mono_error_init (error);
3956 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3959 static char **main_args = NULL;
3960 static int num_main_args = 0;
3963 * mono_runtime_get_main_args:
3965 * Returns: a MonoArray with the arguments passed to the main program
3968 mono_runtime_get_main_args (void)
3970 MONO_REQ_GC_UNSAFE_MODE;
3972 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3973 mono_error_assert_ok (&error);
3978 * mono_runtime_get_main_args:
3979 * @error: set on error
3981 * Returns: a MonoArray with the arguments passed to the main
3982 * program. On failure returns NULL and sets @error.
3985 mono_runtime_get_main_args_checked (MonoError *error)
3989 MonoDomain *domain = mono_domain_get ();
3991 mono_error_init (error);
3993 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3994 return_val_if_nok (error, NULL);
3996 for (i = 0; i < num_main_args; ++i)
3997 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4003 free_main_args (void)
4005 MONO_REQ_GC_NEUTRAL_MODE;
4009 for (i = 0; i < num_main_args; ++i)
4010 g_free (main_args [i]);
4017 * mono_runtime_set_main_args:
4018 * @argc: number of arguments from the command line
4019 * @argv: array of strings from the command line
4021 * Set the command line arguments from an embedding application that doesn't otherwise call
4022 * mono_runtime_run_main ().
4025 mono_runtime_set_main_args (int argc, char* argv[])
4027 MONO_REQ_GC_NEUTRAL_MODE;
4032 main_args = g_new0 (char*, argc);
4033 num_main_args = argc;
4035 for (i = 0; i < argc; ++i) {
4038 utf8_arg = mono_utf8_from_external (argv[i]);
4039 if (utf8_arg == NULL) {
4040 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4041 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4045 main_args [i] = utf8_arg;
4052 * Prepare an array of arguments in order to execute a standard Main()
4053 * method (argc/argv contains the executable name). This method also
4054 * sets the command line argument value needed by System.Environment.
4058 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4060 MONO_REQ_GC_UNSAFE_MODE;
4064 MonoArray *args = NULL;
4065 MonoDomain *domain = mono_domain_get ();
4066 gchar *utf8_fullpath;
4067 MonoMethodSignature *sig;
4069 g_assert (method != NULL);
4071 mono_thread_set_main (mono_thread_current ());
4073 main_args = g_new0 (char*, argc);
4074 num_main_args = argc;
4076 if (!g_path_is_absolute (argv [0])) {
4077 gchar *basename = g_path_get_basename (argv [0]);
4078 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4082 utf8_fullpath = mono_utf8_from_external (fullpath);
4083 if(utf8_fullpath == NULL) {
4084 /* Printing the arg text will cause glib to
4085 * whinge about "Invalid UTF-8", but at least
4086 * its relevant, and shows the problem text
4089 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4090 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4097 utf8_fullpath = mono_utf8_from_external (argv[0]);
4098 if(utf8_fullpath == NULL) {
4099 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4100 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4105 main_args [0] = utf8_fullpath;
4107 for (i = 1; i < argc; ++i) {
4110 utf8_arg=mono_utf8_from_external (argv[i]);
4111 if(utf8_arg==NULL) {
4112 /* Ditto the comment about Invalid UTF-8 here */
4113 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4114 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4118 main_args [i] = utf8_arg;
4123 sig = mono_method_signature (method);
4125 g_print ("Unable to load Main method.\n");
4129 if (sig->param_count) {
4130 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4131 mono_error_assert_ok (&error);
4132 for (i = 0; i < argc; ++i) {
4133 /* The encodings should all work, given that
4134 * we've checked all these args for the
4137 gchar *str = mono_utf8_from_external (argv [i]);
4138 MonoString *arg = mono_string_new (domain, str);
4139 mono_array_setref (args, i, arg);
4143 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4144 mono_error_assert_ok (&error);
4147 mono_assembly_set_main (method->klass->image->assembly);
4153 * mono_runtime_run_main:
4154 * @method: the method to start the application with (usually Main)
4155 * @argc: number of arguments from the command line
4156 * @argv: array of strings from the command line
4157 * @exc: excetption results
4159 * Execute a standard Main() method (argc/argv contains the
4160 * executable name). This method also sets the command line argument value
4161 * needed by System.Environment.
4166 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4169 MONO_REQ_GC_UNSAFE_MODE;
4172 MonoArray *args = prepare_run_main (method, argc, argv);
4175 res = mono_runtime_try_exec_main (method, args, exc);
4177 res = mono_runtime_exec_main_checked (method, args, &error);
4178 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4184 * mono_runtime_run_main_checked:
4185 * @method: the method to start the application with (usually Main)
4186 * @argc: number of arguments from the command line
4187 * @argv: array of strings from the command line
4188 * @error: set on error
4190 * Execute a standard Main() method (argc/argv contains the
4191 * executable name). This method also sets the command line argument value
4192 * needed by System.Environment. On failure sets @error.
4197 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4200 mono_error_init (error);
4201 MonoArray *args = prepare_run_main (method, argc, argv);
4202 return mono_runtime_exec_main_checked (method, args, error);
4206 * mono_runtime_try_run_main:
4207 * @method: the method to start the application with (usually Main)
4208 * @argc: number of arguments from the command line
4209 * @argv: array of strings from the command line
4210 * @exc: set if Main throws an exception
4211 * @error: set if Main can't be executed
4213 * Execute a standard Main() method (argc/argv contains the executable
4214 * name). This method also sets the command line argument value needed
4215 * by System.Environment. On failure sets @error if Main can't be
4216 * executed or @exc if it threw and exception.
4221 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4225 MonoArray *args = prepare_run_main (method, argc, argv);
4226 return mono_runtime_try_exec_main (method, args, exc);
4231 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4233 static MonoMethod *serialize_method;
4239 if (!serialize_method) {
4240 MonoClass *klass = mono_class_get_remoting_services_class ();
4241 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4244 if (!serialize_method) {
4249 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4254 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4255 if (*exc == NULL && !mono_error_ok (&error))
4256 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4258 mono_error_cleanup (&error);
4267 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4269 MONO_REQ_GC_UNSAFE_MODE;
4271 static MonoMethod *deserialize_method;
4277 if (!deserialize_method) {
4278 MonoClass *klass = mono_class_get_remoting_services_class ();
4279 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4281 if (!deserialize_method) {
4289 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4290 if (*exc == NULL && !mono_error_ok (&error))
4291 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4293 mono_error_cleanup (&error);
4301 #ifndef DISABLE_REMOTING
4303 make_transparent_proxy (MonoObject *obj, MonoError *error)
4305 MONO_REQ_GC_UNSAFE_MODE;
4307 static MonoMethod *get_proxy_method;
4309 MonoDomain *domain = mono_domain_get ();
4310 MonoRealProxy *real_proxy;
4311 MonoReflectionType *reflection_type;
4312 MonoTransparentProxy *transparent_proxy;
4314 mono_error_init (error);
4316 if (!get_proxy_method)
4317 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4319 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4321 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4322 return_val_if_nok (error, NULL);
4323 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4324 return_val_if_nok (error, NULL);
4326 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4327 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4329 MonoObject *exc = NULL;
4331 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4332 if (exc != NULL && is_ok (error))
4333 mono_error_set_exception_instance (error, (MonoException*)exc);
4335 return (MonoObject*) transparent_proxy;
4337 #endif /* DISABLE_REMOTING */
4340 * mono_object_xdomain_representation
4342 * @target_domain: a domain
4343 * @error: set on error.
4345 * Creates a representation of obj in the domain target_domain. This
4346 * is either a copy of obj arrived through via serialization and
4347 * deserialization or a proxy, depending on whether the object is
4348 * serializable or marshal by ref. obj must not be in target_domain.
4350 * If the object cannot be represented in target_domain, NULL is
4351 * returned and @error is set appropriately.
4354 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4356 MONO_REQ_GC_UNSAFE_MODE;
4358 mono_error_init (error);
4359 MonoObject *deserialized = NULL;
4361 #ifndef DISABLE_REMOTING
4362 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4363 deserialized = make_transparent_proxy (obj, error);
4368 gboolean failure = FALSE;
4369 MonoDomain *domain = mono_domain_get ();
4370 MonoObject *serialized;
4371 MonoObject *exc = NULL;
4373 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4374 serialized = serialize_object (obj, &failure, &exc);
4375 mono_domain_set_internal_with_options (target_domain, FALSE);
4377 deserialized = deserialize_object (serialized, &failure, &exc);
4378 if (domain != target_domain)
4379 mono_domain_set_internal_with_options (domain, FALSE);
4381 mono_error_set_exception_instance (error, (MonoException*)exc);
4384 return deserialized;
4387 /* Used in call_unhandled_exception_delegate */
4389 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4391 MONO_REQ_GC_UNSAFE_MODE;
4393 mono_error_init (error);
4396 MonoMethod *method = NULL;
4397 MonoBoolean is_terminating = TRUE;
4400 klass = mono_class_get_unhandled_exception_event_args_class ();
4401 mono_class_init (klass);
4403 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4404 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4408 args [1] = &is_terminating;
4410 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4411 return_val_if_nok (error, NULL);
4413 mono_runtime_invoke_checked (method, obj, args, error);
4414 return_val_if_nok (error, NULL);
4419 /* Used in mono_unhandled_exception */
4421 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4422 MONO_REQ_GC_UNSAFE_MODE;
4425 MonoObject *e = NULL;
4427 MonoDomain *current_domain = mono_domain_get ();
4429 if (domain != current_domain)
4430 mono_domain_set_internal_with_options (domain, FALSE);
4432 g_assert (domain == mono_object_domain (domain->domain));
4434 if (mono_object_domain (exc) != domain) {
4436 exc = mono_object_xdomain_representation (exc, domain, &error);
4438 if (!is_ok (&error)) {
4439 MonoError inner_error;
4440 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4441 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4442 mono_error_assert_ok (&inner_error);
4444 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4445 "System.Runtime.Serialization", "SerializationException",
4446 "Could not serialize unhandled exception.");
4450 g_assert (mono_object_domain (exc) == domain);
4452 pa [0] = domain->domain;
4453 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4454 mono_error_assert_ok (&error);
4455 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4456 if (!is_ok (&error)) {
4458 e = (MonoObject*)mono_error_convert_to_exception (&error);
4460 mono_error_cleanup (&error);
4463 if (domain != current_domain)
4464 mono_domain_set_internal_with_options (current_domain, FALSE);
4467 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4468 if (!mono_error_ok (&error)) {
4469 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4470 mono_error_cleanup (&error);
4472 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4478 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4481 * mono_runtime_unhandled_exception_policy_set:
4482 * @policy: the new policy
4484 * This is a VM internal routine.
4486 * Sets the runtime policy for handling unhandled exceptions.
4489 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4490 runtime_unhandled_exception_policy = policy;
4494 * mono_runtime_unhandled_exception_policy_get:
4496 * This is a VM internal routine.
4498 * Gets the runtime policy for handling unhandled exceptions.
4500 MonoRuntimeUnhandledExceptionPolicy
4501 mono_runtime_unhandled_exception_policy_get (void) {
4502 return runtime_unhandled_exception_policy;
4506 * mono_unhandled_exception:
4507 * @exc: exception thrown
4509 * This is a VM internal routine.
4511 * We call this function when we detect an unhandled exception
4512 * in the default domain.
4514 * It invokes the * UnhandledException event in AppDomain or prints
4515 * a warning to the console
4518 mono_unhandled_exception (MonoObject *exc)
4520 MONO_REQ_GC_UNSAFE_MODE;
4523 MonoClassField *field;
4524 MonoDomain *current_domain, *root_domain;
4525 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4527 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4530 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4533 current_domain = mono_domain_get ();
4534 root_domain = mono_get_root_domain ();
4536 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4537 mono_error_assert_ok (&error);
4538 if (current_domain != root_domain) {
4539 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4540 mono_error_assert_ok (&error);
4543 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4544 mono_print_unhandled_exception (exc);
4546 /* unhandled exception callbacks must not be aborted */
4547 mono_threads_begin_abort_protected_block ();
4548 if (root_appdomain_delegate)
4549 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4550 if (current_appdomain_delegate)
4551 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4552 mono_threads_end_abort_protected_block ();
4555 /* set exitcode only if we will abort the process */
4556 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4557 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4559 mono_environment_exitcode_set (1);
4564 * mono_runtime_exec_managed_code:
4565 * @domain: Application domain
4566 * @main_func: function to invoke from the execution thread
4567 * @main_args: parameter to the main_func
4569 * Launch a new thread to execute a function
4571 * main_func is called back from the thread with main_args as the
4572 * parameter. The callback function is expected to start Main()
4573 * eventually. This function then waits for all managed threads to
4575 * It is not necesseray anymore to execute managed code in a subthread,
4576 * so this function should not be used anymore by default: just
4577 * execute the code and then call mono_thread_manage ().
4580 mono_runtime_exec_managed_code (MonoDomain *domain,
4581 MonoMainThreadFunc main_func,
4585 mono_thread_create_checked (domain, main_func, main_args, &error);
4586 mono_error_assert_ok (&error);
4588 mono_thread_manage ();
4592 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4594 MonoInternalThread* thread = mono_thread_internal_current ();
4595 MonoCustomAttrInfo* cinfo;
4596 gboolean has_stathread_attribute;
4598 if (!domain->entry_assembly) {
4600 MonoAssembly *assembly;
4602 assembly = method->klass->image->assembly;
4603 domain->entry_assembly = assembly;
4604 /* Domains created from another domain already have application_base and configuration_file set */
4605 if (domain->setup->application_base == NULL) {
4606 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4609 if (domain->setup->configuration_file == NULL) {
4610 str = g_strconcat (assembly->image->name, ".config", NULL);
4611 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4613 mono_domain_set_options_from_config (domain);
4617 MonoError cattr_error;
4618 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4619 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4621 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4623 mono_custom_attrs_free (cinfo);
4625 has_stathread_attribute = FALSE;
4627 if (has_stathread_attribute) {
4628 thread->apartment_state = ThreadApartmentState_STA;
4630 thread->apartment_state = ThreadApartmentState_MTA;
4632 mono_thread_init_apartment_state ();
4637 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4639 MONO_REQ_GC_UNSAFE_MODE;
4644 mono_error_init (error);
4649 /* FIXME: check signature of method */
4650 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4652 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4654 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4657 mono_environment_exitcode_set (rval);
4659 mono_runtime_invoke_checked (method, NULL, pa, error);
4671 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4673 MONO_REQ_GC_UNSAFE_MODE;
4683 /* FIXME: check signature of method */
4684 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4685 MonoError inner_error;
4687 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4688 if (*exc == NULL && !mono_error_ok (&inner_error))
4689 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4691 mono_error_cleanup (&inner_error);
4694 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4698 mono_environment_exitcode_set (rval);
4700 MonoError inner_error;
4701 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4702 if (*exc == NULL && !mono_error_ok (&inner_error))
4703 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4705 mono_error_cleanup (&inner_error);
4710 /* If the return type of Main is void, only
4711 * set the exitcode if an exception was thrown
4712 * (we don't want to blow away an
4713 * explicitly-set exit code)
4716 mono_environment_exitcode_set (rval);
4724 * Execute a standard Main() method (args doesn't contain the
4728 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4731 prepare_thread_to_exec_main (mono_object_domain (args), method);
4733 int rval = do_try_exec_main (method, args, exc);
4736 int rval = do_exec_main_checked (method, args, &error);
4737 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4743 * Execute a standard Main() method (args doesn't contain the
4746 * On failure sets @error
4749 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4751 mono_error_init (error);
4752 prepare_thread_to_exec_main (mono_object_domain (args), method);
4753 return do_exec_main_checked (method, args, error);
4757 * Execute a standard Main() method (args doesn't contain the
4760 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4763 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4765 prepare_thread_to_exec_main (mono_object_domain (args), method);
4766 return do_try_exec_main (method, args, exc);
4771 /** invoke_array_extract_argument:
4772 * @params: array of arguments to the method.
4773 * @i: the index of the argument to extract.
4774 * @t: ith type from the method signature.
4775 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4776 * @error: set on error.
4778 * Given an array of method arguments, return the ith one using the corresponding type
4779 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4781 * On failure sets @error and returns NULL.
4784 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4786 MonoType *t_orig = t;
4787 gpointer result = NULL;
4788 mono_error_init (error);
4793 case MONO_TYPE_BOOLEAN:
4796 case MONO_TYPE_CHAR:
4805 case MONO_TYPE_VALUETYPE:
4806 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4807 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4808 result = mono_array_get (params, MonoObject*, i);
4810 *has_byref_nullables = TRUE;
4812 /* MS seems to create the objects if a null is passed in */
4813 if (!mono_array_get (params, MonoObject*, i)) {
4814 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4815 return_val_if_nok (error, NULL);
4816 mono_array_setref (params, i, o);
4821 * We can't pass the unboxed vtype byref to the callee, since
4822 * that would mean the callee would be able to modify boxed
4823 * primitive types. So we (and MS) make a copy of the boxed
4824 * object, pass that to the callee, and replace the original
4825 * boxed object in the arg array with the copy.
4827 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4828 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4829 return_val_if_nok (error, NULL);
4830 mono_array_setref (params, i, copy);
4833 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4836 case MONO_TYPE_STRING:
4837 case MONO_TYPE_OBJECT:
4838 case MONO_TYPE_CLASS:
4839 case MONO_TYPE_ARRAY:
4840 case MONO_TYPE_SZARRAY:
4842 result = mono_array_addr (params, MonoObject*, i);
4843 // FIXME: I need to check this code path
4845 result = mono_array_get (params, MonoObject*, i);
4847 case MONO_TYPE_GENERICINST:
4849 t = &t->data.generic_class->container_class->this_arg;
4851 t = &t->data.generic_class->container_class->byval_arg;
4853 case MONO_TYPE_PTR: {
4856 /* The argument should be an IntPtr */
4857 arg = mono_array_get (params, MonoObject*, i);
4861 g_assert (arg->vtable->klass == mono_defaults.int_class);
4862 result = ((MonoIntPtr*)arg)->m_value;
4867 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4872 * mono_runtime_invoke_array:
4873 * @method: method to invoke
4874 * @obJ: object instance
4875 * @params: arguments to the method
4876 * @exc: exception information.
4878 * Invokes the method represented by @method on the object @obj.
4880 * obj is the 'this' pointer, it should be NULL for static
4881 * methods, a MonoObject* for object instances and a pointer to
4882 * the value type for value types.
4884 * The params array contains the arguments to the method with the
4885 * same convention: MonoObject* pointers for object instances and
4886 * pointers to the value type otherwise. The _invoke_array
4887 * variant takes a C# object[] as the params argument (MonoArray
4888 * *params): in this case the value types are boxed inside the
4889 * respective reference representation.
4891 * From unmanaged code you'll usually use the
4892 * mono_runtime_invoke_checked() variant.
4894 * Note that this function doesn't handle virtual methods for
4895 * you, it will exec the exact method you pass: we still need to
4896 * expose a function to lookup the derived class implementation
4897 * of a virtual method (there are examples of this in the code,
4900 * You can pass NULL as the exc argument if you don't want to
4901 * catch exceptions, otherwise, *exc will be set to the exception
4902 * thrown, if any. if an exception is thrown, you can't use the
4903 * MonoObject* result from the function.
4905 * If the method returns a value type, it is boxed in an object
4909 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4914 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4916 mono_error_cleanup (&error);
4919 if (!is_ok (&error))
4920 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4924 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4925 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4931 * mono_runtime_invoke_array_checked:
4932 * @method: method to invoke
4933 * @obJ: object instance
4934 * @params: arguments to the method
4935 * @error: set on failure.
4937 * Invokes the method represented by @method on the object @obj.
4939 * obj is the 'this' pointer, it should be NULL for static
4940 * methods, a MonoObject* for object instances and a pointer to
4941 * the value type for value types.
4943 * The params array contains the arguments to the method with the
4944 * same convention: MonoObject* pointers for object instances and
4945 * pointers to the value type otherwise. The _invoke_array
4946 * variant takes a C# object[] as the params argument (MonoArray
4947 * *params): in this case the value types are boxed inside the
4948 * respective reference representation.
4950 * From unmanaged code you'll usually use the
4951 * mono_runtime_invoke_checked() variant.
4953 * Note that this function doesn't handle virtual methods for
4954 * you, it will exec the exact method you pass: we still need to
4955 * expose a function to lookup the derived class implementation
4956 * of a virtual method (there are examples of this in the code,
4959 * On failure or exception, @error will be set. In that case, you
4960 * can't use the MonoObject* result from the function.
4962 * If the method returns a value type, it is boxed in an object
4966 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4969 mono_error_init (error);
4970 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4974 * mono_runtime_try_invoke_array:
4975 * @method: method to invoke
4976 * @obJ: object instance
4977 * @params: arguments to the method
4978 * @exc: exception information.
4979 * @error: set on failure.
4981 * Invokes the method represented by @method on the object @obj.
4983 * obj is the 'this' pointer, it should be NULL for static
4984 * methods, a MonoObject* for object instances and a pointer to
4985 * the value type for value types.
4987 * The params array contains the arguments to the method with the
4988 * same convention: MonoObject* pointers for object instances and
4989 * pointers to the value type otherwise. The _invoke_array
4990 * variant takes a C# object[] as the params argument (MonoArray
4991 * *params): in this case the value types are boxed inside the
4992 * respective reference representation.
4994 * From unmanaged code you'll usually use the
4995 * mono_runtime_invoke_checked() variant.
4997 * Note that this function doesn't handle virtual methods for
4998 * you, it will exec the exact method you pass: we still need to
4999 * expose a function to lookup the derived class implementation
5000 * of a virtual method (there are examples of this in the code,
5003 * You can pass NULL as the exc argument if you don't want to catch
5004 * exceptions, otherwise, *exc will be set to the exception thrown, if
5005 * any. On other failures, @error will be set. If an exception is
5006 * thrown or there's an error, you can't use the MonoObject* result
5007 * from the function.
5009 * If the method returns a value type, it is boxed in an object
5013 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5014 MonoObject **exc, MonoError *error)
5016 MONO_REQ_GC_UNSAFE_MODE;
5018 mono_error_init (error);
5020 MonoMethodSignature *sig = mono_method_signature (method);
5021 gpointer *pa = NULL;
5024 gboolean has_byref_nullables = FALSE;
5026 if (NULL != params) {
5027 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5028 for (i = 0; i < mono_array_length (params); i++) {
5029 MonoType *t = sig->params [i];
5030 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5031 return_val_if_nok (error, NULL);
5035 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5038 if (mono_class_is_nullable (method->klass)) {
5039 /* Need to create a boxed vtype instead */
5045 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5050 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5051 mono_error_assert_ok (error);
5052 g_assert (obj); /*maybe we should raise a TLE instead?*/
5053 #ifndef DISABLE_REMOTING
5054 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5055 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5058 if (method->klass->valuetype)
5059 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5062 } else if (method->klass->valuetype) {
5063 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5064 return_val_if_nok (error, NULL);
5068 mono_runtime_try_invoke (method, o, pa, exc, error);
5070 mono_runtime_invoke_checked (method, o, pa, error);
5073 return (MonoObject *)obj;
5075 if (mono_class_is_nullable (method->klass)) {
5076 MonoObject *nullable;
5078 /* Convert the unboxed vtype into a Nullable structure */
5079 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5080 return_val_if_nok (error, NULL);
5082 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5083 return_val_if_nok (error, NULL);
5084 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5085 obj = mono_object_unbox (nullable);
5088 /* obj must be already unboxed if needed */
5090 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5092 res = mono_runtime_invoke_checked (method, obj, pa, error);
5094 return_val_if_nok (error, NULL);
5096 if (sig->ret->type == MONO_TYPE_PTR) {
5097 MonoClass *pointer_class;
5098 static MonoMethod *box_method;
5100 MonoObject *box_exc;
5103 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5104 * convert it to a Pointer object.
5106 pointer_class = mono_class_get_pointer_class ();
5108 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5110 g_assert (res->vtable->klass == mono_defaults.int_class);
5111 box_args [0] = ((MonoIntPtr*)res)->m_value;
5112 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5113 return_val_if_nok (error, NULL);
5115 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5116 g_assert (box_exc == NULL);
5117 mono_error_assert_ok (error);
5120 if (has_byref_nullables) {
5122 * The runtime invoke wrapper already converted byref nullables back,
5123 * and stored them in pa, we just need to copy them back to the
5126 for (i = 0; i < mono_array_length (params); i++) {
5127 MonoType *t = sig->params [i];
5129 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5130 mono_array_setref (params, i, pa [i]);
5140 * @klass: the class of the object that we want to create
5142 * Returns: a newly created object whose definition is
5143 * looked up using @klass. This will not invoke any constructors,
5144 * so the consumer of this routine has to invoke any constructors on
5145 * its own to initialize the object.
5147 * It returns NULL on failure.
5150 mono_object_new (MonoDomain *domain, MonoClass *klass)
5152 MONO_REQ_GC_UNSAFE_MODE;
5156 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5158 mono_error_cleanup (&error);
5163 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5165 MONO_REQ_GC_UNSAFE_MODE;
5169 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5171 mono_error_set_pending_exception (&error);
5176 * mono_object_new_checked:
5177 * @klass: the class of the object that we want to create
5178 * @error: set on error
5180 * Returns: a newly created object whose definition is
5181 * looked up using @klass. This will not invoke any constructors,
5182 * so the consumer of this routine has to invoke any constructors on
5183 * its own to initialize the object.
5185 * It returns NULL on failure and sets @error.
5188 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5190 MONO_REQ_GC_UNSAFE_MODE;
5194 vtable = mono_class_vtable (domain, klass);
5195 g_assert (vtable); /* FIXME don't swallow the error */
5197 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5202 * mono_object_new_pinned:
5204 * Same as mono_object_new, but the returned object will be pinned.
5205 * For SGEN, these objects will only be freed at appdomain unload.
5208 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5210 MONO_REQ_GC_UNSAFE_MODE;
5214 mono_error_init (error);
5216 vtable = mono_class_vtable (domain, klass);
5217 g_assert (vtable); /* FIXME don't swallow the error */
5219 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5221 if (G_UNLIKELY (!o))
5222 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5223 else if (G_UNLIKELY (vtable->klass->has_finalize))
5224 mono_object_register_finalizer (o);
5230 * mono_object_new_specific:
5231 * @vtable: the vtable of the object that we want to create
5233 * Returns: A newly created object with class and domain specified
5237 mono_object_new_specific (MonoVTable *vtable)
5240 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5241 mono_error_cleanup (&error);
5247 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5249 MONO_REQ_GC_UNSAFE_MODE;
5253 mono_error_init (error);
5255 /* check for is_com_object for COM Interop */
5256 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5259 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5262 MonoClass *klass = mono_class_get_activation_services_class ();
5265 mono_class_init (klass);
5267 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5269 mono_error_set_not_supported (error, "Linked away.");
5272 vtable->domain->create_proxy_for_type_method = im;
5275 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5276 if (!mono_error_ok (error))
5279 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5280 if (!mono_error_ok (error))
5287 return mono_object_new_alloc_specific_checked (vtable, error);
5291 ves_icall_object_new_specific (MonoVTable *vtable)
5294 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5295 mono_error_set_pending_exception (&error);
5301 * mono_object_new_alloc_specific:
5302 * @vtable: virtual table for the object.
5304 * This function allocates a new `MonoObject` with the type derived
5305 * from the @vtable information. If the class of this object has a
5306 * finalizer, then the object will be tracked for finalization.
5308 * This method might raise an exception on errors. Use the
5309 * `mono_object_new_fast_checked` method if you want to manually raise
5312 * Returns: the allocated object.
5315 mono_object_new_alloc_specific (MonoVTable *vtable)
5318 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5319 mono_error_cleanup (&error);
5325 * mono_object_new_alloc_specific_checked:
5326 * @vtable: virtual table for the object.
5327 * @error: holds the error return value.
5329 * This function allocates a new `MonoObject` with the type derived
5330 * from the @vtable information. If the class of this object has a
5331 * finalizer, then the object will be tracked for finalization.
5333 * If there is not enough memory, the @error parameter will be set
5334 * and will contain a user-visible message with the amount of bytes
5335 * that were requested.
5337 * Returns: the allocated object, or NULL if there is not enough memory
5341 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5343 MONO_REQ_GC_UNSAFE_MODE;
5347 mono_error_init (error);
5349 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5351 if (G_UNLIKELY (!o))
5352 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5353 else if (G_UNLIKELY (vtable->klass->has_finalize))
5354 mono_object_register_finalizer (o);
5360 * mono_object_new_fast:
5361 * @vtable: virtual table for the object.
5363 * This function allocates a new `MonoObject` with the type derived
5364 * from the @vtable information. The returned object is not tracked
5365 * for finalization. If your object implements a finalizer, you should
5366 * use `mono_object_new_alloc_specific` instead.
5368 * This method might raise an exception on errors. Use the
5369 * `mono_object_new_fast_checked` method if you want to manually raise
5372 * Returns: the allocated object.
5375 mono_object_new_fast (MonoVTable *vtable)
5378 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5379 mono_error_cleanup (&error);
5385 * mono_object_new_fast_checked:
5386 * @vtable: virtual table for the object.
5387 * @error: holds the error return value.
5389 * This function allocates a new `MonoObject` with the type derived
5390 * from the @vtable information. The returned object is not tracked
5391 * for finalization. If your object implements a finalizer, you should
5392 * use `mono_object_new_alloc_specific_checked` instead.
5394 * If there is not enough memory, the @error parameter will be set
5395 * and will contain a user-visible message with the amount of bytes
5396 * that were requested.
5398 * Returns: the allocated object, or NULL if there is not enough memory
5402 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5404 MONO_REQ_GC_UNSAFE_MODE;
5408 mono_error_init (error);
5410 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5412 if (G_UNLIKELY (!o))
5413 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5419 ves_icall_object_new_fast (MonoVTable *vtable)
5422 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5423 mono_error_set_pending_exception (&error);
5429 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5431 MONO_REQ_GC_UNSAFE_MODE;
5435 mono_error_init (error);
5437 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5439 if (G_UNLIKELY (!o))
5440 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5441 else if (G_UNLIKELY (vtable->klass->has_finalize))
5442 mono_object_register_finalizer (o);
5448 * mono_class_get_allocation_ftn:
5450 * @for_box: the object will be used for boxing
5451 * @pass_size_in_words:
5453 * Return the allocation function appropriate for the given class.
5457 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5459 MONO_REQ_GC_NEUTRAL_MODE;
5461 *pass_size_in_words = FALSE;
5463 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5464 return ves_icall_object_new_specific;
5466 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5468 return ves_icall_object_new_fast;
5471 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5472 * of the overhead of parameter passing.
5475 *pass_size_in_words = TRUE;
5476 #ifdef GC_REDIRECT_TO_LOCAL
5477 return GC_local_gcj_fast_malloc;
5479 return GC_gcj_fast_malloc;
5484 return ves_icall_object_new_specific;
5488 * mono_object_new_from_token:
5489 * @image: Context where the type_token is hosted
5490 * @token: a token of the type that we want to create
5492 * Returns: A newly created object whose definition is
5493 * looked up using @token in the @image image
5496 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5498 MONO_REQ_GC_UNSAFE_MODE;
5504 klass = mono_class_get_checked (image, token, &error);
5505 mono_error_assert_ok (&error);
5507 result = mono_object_new_checked (domain, klass, &error);
5509 mono_error_cleanup (&error);
5516 * mono_object_clone:
5517 * @obj: the object to clone
5519 * Returns: A newly created object who is a shallow copy of @obj
5522 mono_object_clone (MonoObject *obj)
5525 MonoObject *o = mono_object_clone_checked (obj, &error);
5526 mono_error_cleanup (&error);
5532 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5534 MONO_REQ_GC_UNSAFE_MODE;
5539 mono_error_init (error);
5541 size = obj->vtable->klass->instance_size;
5543 if (obj->vtable->klass->rank)
5544 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5546 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5548 if (G_UNLIKELY (!o)) {
5549 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5553 /* If the object doesn't contain references this will do a simple memmove. */
5554 mono_gc_wbarrier_object_copy (o, obj);
5556 if (obj->vtable->klass->has_finalize)
5557 mono_object_register_finalizer (o);
5562 * mono_array_full_copy:
5563 * @src: source array to copy
5564 * @dest: destination array
5566 * Copies the content of one array to another with exactly the same type and size.
5569 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5571 MONO_REQ_GC_UNSAFE_MODE;
5574 MonoClass *klass = src->obj.vtable->klass;
5576 g_assert (klass == dest->obj.vtable->klass);
5578 size = mono_array_length (src);
5579 g_assert (size == mono_array_length (dest));
5580 size *= mono_array_element_size (klass);
5582 if (klass->element_class->valuetype) {
5583 if (klass->element_class->has_references)
5584 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5586 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5588 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5591 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5596 * mono_array_clone_in_domain:
5597 * @domain: the domain in which the array will be cloned into
5598 * @array: the array to clone
5599 * @error: set on error
5601 * This routine returns a copy of the array that is hosted on the
5602 * specified MonoDomain. On failure returns NULL and sets @error.
5605 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5607 MONO_REQ_GC_UNSAFE_MODE;
5612 MonoClass *klass = array->obj.vtable->klass;
5614 mono_error_init (error);
5616 if (array->bounds == NULL) {
5617 size = mono_array_length (array);
5618 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5619 return_val_if_nok (error, NULL);
5621 size *= mono_array_element_size (klass);
5623 if (klass->element_class->valuetype) {
5624 if (klass->element_class->has_references)
5625 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5627 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5629 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5632 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5637 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5638 size = mono_array_element_size (klass);
5639 for (i = 0; i < klass->rank; ++i) {
5640 sizes [i] = array->bounds [i].length;
5641 size *= array->bounds [i].length;
5642 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5644 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5645 return_val_if_nok (error, NULL);
5647 if (klass->element_class->valuetype) {
5648 if (klass->element_class->has_references)
5649 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5651 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5653 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5656 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5664 * @array: the array to clone
5666 * Returns: A newly created array who is a shallow copy of @array
5669 mono_array_clone (MonoArray *array)
5671 MONO_REQ_GC_UNSAFE_MODE;
5674 MonoArray *result = mono_array_clone_checked (array, &error);
5675 mono_error_cleanup (&error);
5680 * mono_array_clone_checked:
5681 * @array: the array to clone
5682 * @error: set on error
5684 * Returns: A newly created array who is a shallow copy of @array. On
5685 * failure returns NULL and sets @error.
5688 mono_array_clone_checked (MonoArray *array, MonoError *error)
5691 MONO_REQ_GC_UNSAFE_MODE;
5692 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5695 /* helper macros to check for overflow when calculating the size of arrays */
5696 #ifdef MONO_BIG_ARRAYS
5697 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5698 #define MYGUINT_MAX MYGUINT64_MAX
5699 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5700 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5701 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5702 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5703 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5705 #define MYGUINT32_MAX 4294967295U
5706 #define MYGUINT_MAX MYGUINT32_MAX
5707 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5708 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5709 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5710 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5711 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5715 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5717 MONO_REQ_GC_NEUTRAL_MODE;
5721 byte_len = mono_array_element_size (klass);
5722 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5725 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5727 byte_len += MONO_SIZEOF_MONO_ARRAY;
5735 * mono_array_new_full:
5736 * @domain: domain where the object is created
5737 * @array_class: array class
5738 * @lengths: lengths for each dimension in the array
5739 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5741 * This routine creates a new array objects with the given dimensions,
5742 * lower bounds and type.
5745 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5748 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5749 mono_error_cleanup (&error);
5755 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5757 MONO_REQ_GC_UNSAFE_MODE;
5759 uintptr_t byte_len = 0, len, bounds_size;
5762 MonoArrayBounds *bounds;
5766 mono_error_init (error);
5768 if (!array_class->inited)
5769 mono_class_init (array_class);
5773 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5774 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5776 if (len > MONO_ARRAY_MAX_INDEX) {
5777 mono_error_set_generic_error (error, "System", "OverflowException", "");
5782 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5784 for (i = 0; i < array_class->rank; ++i) {
5785 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5786 mono_error_set_generic_error (error, "System", "OverflowException", "");
5789 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5790 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5797 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5798 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5804 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5805 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5808 byte_len = (byte_len + 3) & ~3;
5809 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5810 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5813 byte_len += bounds_size;
5816 * Following three lines almost taken from mono_object_new ():
5817 * they need to be kept in sync.
5819 vtable = mono_class_vtable_full (domain, array_class, error);
5820 return_val_if_nok (error, NULL);
5823 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5825 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5827 if (G_UNLIKELY (!o)) {
5828 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5832 array = (MonoArray*)o;
5834 bounds = array->bounds;
5837 for (i = 0; i < array_class->rank; ++i) {
5838 bounds [i].length = lengths [i];
5840 bounds [i].lower_bound = lower_bounds [i];
5849 * @domain: domain where the object is created
5850 * @eclass: element class
5851 * @n: number of array elements
5853 * This routine creates a new szarray with @n elements of type @eclass.
5856 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5858 MONO_REQ_GC_UNSAFE_MODE;
5861 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5862 mono_error_cleanup (&error);
5867 * mono_array_new_checked:
5868 * @domain: domain where the object is created
5869 * @eclass: element class
5870 * @n: number of array elements
5871 * @error: set on error
5873 * This routine creates a new szarray with @n elements of type @eclass.
5874 * On failure returns NULL and sets @error.
5877 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5881 mono_error_init (error);
5883 ac = mono_array_class_get (eclass, 1);
5886 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5887 return_val_if_nok (error, NULL);
5889 return mono_array_new_specific_checked (vtable, n, error);
5893 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5896 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5897 mono_error_set_pending_exception (&error);
5903 * mono_array_new_specific:
5904 * @vtable: a vtable in the appropriate domain for an initialized class
5905 * @n: number of array elements
5907 * This routine is a fast alternative to mono_array_new() for code which
5908 * can be sure about the domain it operates in.
5911 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5914 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5915 mono_error_cleanup (&error);
5921 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5923 MONO_REQ_GC_UNSAFE_MODE;
5928 mono_error_init (error);
5930 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5931 mono_error_set_generic_error (error, "System", "OverflowException", "");
5935 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5936 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5939 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5941 if (G_UNLIKELY (!o)) {
5942 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5946 return (MonoArray*)o;
5950 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5953 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5954 mono_error_set_pending_exception (&error);
5960 * mono_string_new_utf16:
5961 * @text: a pointer to an utf16 string
5962 * @len: the length of the string
5964 * Returns: A newly created string object which contains @text.
5967 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5969 MONO_REQ_GC_UNSAFE_MODE;
5972 MonoString *res = NULL;
5973 res = mono_string_new_utf16_checked (domain, text, len, &error);
5974 mono_error_cleanup (&error);
5980 * mono_string_new_utf16_checked:
5981 * @text: a pointer to an utf16 string
5982 * @len: the length of the string
5983 * @error: written on error.
5985 * Returns: A newly created string object which contains @text.
5986 * On error, returns NULL and sets @error.
5989 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5991 MONO_REQ_GC_UNSAFE_MODE;
5995 mono_error_init (error);
5997 s = mono_string_new_size_checked (domain, len, error);
5999 memcpy (mono_string_chars (s), text, len * 2);
6005 * mono_string_new_utf32:
6006 * @text: a pointer to an utf32 string
6007 * @len: the length of the string
6008 * @error: set on failure.
6010 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6013 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6015 MONO_REQ_GC_UNSAFE_MODE;
6018 mono_unichar2 *utf16_output = NULL;
6019 gint32 utf16_len = 0;
6020 GError *gerror = NULL;
6021 glong items_written;
6023 mono_error_init (error);
6024 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6027 g_error_free (gerror);
6029 while (utf16_output [utf16_len]) utf16_len++;
6031 s = mono_string_new_size_checked (domain, utf16_len, error);
6032 return_val_if_nok (error, NULL);
6034 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6036 g_free (utf16_output);
6042 * mono_string_new_utf32:
6043 * @text: a pointer to an utf32 string
6044 * @len: the length of the string
6046 * Returns: A newly created string object which contains @text.
6049 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6052 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6053 mono_error_cleanup (&error);
6058 * mono_string_new_size:
6059 * @text: a pointer to an utf16 string
6060 * @len: the length of the string
6062 * Returns: A newly created string object of @len
6065 mono_string_new_size (MonoDomain *domain, gint32 len)
6068 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6069 mono_error_cleanup (&error);
6075 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6077 MONO_REQ_GC_UNSAFE_MODE;
6083 mono_error_init (error);
6085 /* check for overflow */
6086 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6087 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6091 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6092 g_assert (size > 0);
6094 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6097 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6099 if (G_UNLIKELY (!s)) {
6100 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6108 * mono_string_new_len:
6109 * @text: a pointer to an utf8 string
6110 * @length: number of bytes in @text to consider
6112 * Returns: A newly created string object which contains @text.
6115 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6117 MONO_REQ_GC_UNSAFE_MODE;
6120 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6121 mono_error_cleanup (&error);
6126 * mono_string_new_len_checked:
6127 * @text: a pointer to an utf8 string
6128 * @length: number of bytes in @text to consider
6129 * @error: set on error
6131 * Returns: A newly created string object which contains @text. On
6132 * failure returns NULL and sets @error.
6135 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6137 MONO_REQ_GC_UNSAFE_MODE;
6139 mono_error_init (error);
6141 GError *eg_error = NULL;
6142 MonoString *o = NULL;
6144 glong items_written;
6146 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6149 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6151 g_error_free (eg_error);
6160 * @text: a pointer to an utf8 string
6162 * Returns: A newly created string object which contains @text.
6164 * This function asserts if it cannot allocate a new string.
6166 * @deprecated Use mono_string_new_checked in new code.
6169 mono_string_new (MonoDomain *domain, const char *text)
6172 MonoString *res = NULL;
6173 res = mono_string_new_checked (domain, text, &error);
6174 mono_error_assert_ok (&error);
6179 * mono_string_new_checked:
6180 * @text: a pointer to an utf8 string
6181 * @merror: set on error
6183 * Returns: A newly created string object which contains @text.
6184 * On error returns NULL and sets @merror.
6187 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6189 MONO_REQ_GC_UNSAFE_MODE;
6191 GError *eg_error = NULL;
6192 MonoString *o = NULL;
6194 glong items_written;
6197 mono_error_init (error);
6201 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6204 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6206 g_error_free (eg_error);
6210 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6215 MonoString *o = NULL;
6217 if (!g_utf8_validate (text, -1, &end)) {
6218 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6222 len = g_utf8_strlen (text, -1);
6223 o = mono_string_new_size_checked (domain, len, error);
6226 str = mono_string_chars (o);
6228 while (text < end) {
6229 *str++ = g_utf8_get_char (text);
6230 text = g_utf8_next_char (text);
6239 * mono_string_new_wrapper:
6240 * @text: pointer to utf8 characters.
6242 * Helper function to create a string object from @text in the current domain.
6245 mono_string_new_wrapper (const char *text)
6247 MONO_REQ_GC_UNSAFE_MODE;
6249 MonoDomain *domain = mono_domain_get ();
6252 return mono_string_new (domain, text);
6259 * @class: the class of the value
6260 * @value: a pointer to the unboxed data
6262 * Returns: A newly created object which contains @value.
6265 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6268 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6269 mono_error_cleanup (&error);
6274 * mono_value_box_checked:
6275 * @domain: the domain of the new object
6276 * @class: the class of the value
6277 * @value: a pointer to the unboxed data
6278 * @error: set on error
6280 * Returns: A newly created object which contains @value. On failure
6281 * returns NULL and sets @error.
6284 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6286 MONO_REQ_GC_UNSAFE_MODE;
6291 mono_error_init (error);
6293 g_assert (klass->valuetype);
6294 if (mono_class_is_nullable (klass))
6295 return mono_nullable_box ((guint8 *)value, klass, error);
6297 vtable = mono_class_vtable (domain, klass);
6300 size = mono_class_instance_size (klass);
6301 res = mono_object_new_alloc_specific_checked (vtable, error);
6302 return_val_if_nok (error, NULL);
6304 size = size - sizeof (MonoObject);
6307 g_assert (size == mono_class_value_size (klass, NULL));
6308 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6310 #if NO_UNALIGNED_ACCESS
6311 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6315 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6318 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6321 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6324 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6327 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6331 if (klass->has_finalize) {
6332 mono_object_register_finalizer (res);
6333 return_val_if_nok (error, NULL);
6340 * @dest: destination pointer
6341 * @src: source pointer
6342 * @klass: a valuetype class
6344 * Copy a valuetype from @src to @dest. This function must be used
6345 * when @klass contains references fields.
6348 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6350 MONO_REQ_GC_UNSAFE_MODE;
6352 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6356 * mono_value_copy_array:
6357 * @dest: destination array
6358 * @dest_idx: index in the @dest array
6359 * @src: source pointer
6360 * @count: number of items
6362 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6363 * This function must be used when @klass contains references fields.
6364 * Overlap is handled.
6367 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6369 MONO_REQ_GC_UNSAFE_MODE;
6371 int size = mono_array_element_size (dest->obj.vtable->klass);
6372 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6373 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6374 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6378 * mono_object_get_domain:
6379 * @obj: object to query
6381 * Returns: the MonoDomain where the object is hosted
6384 mono_object_get_domain (MonoObject *obj)
6386 MONO_REQ_GC_UNSAFE_MODE;
6388 return mono_object_domain (obj);
6392 * mono_object_get_class:
6393 * @obj: object to query
6395 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6397 * Returns: the MonoClass of the object.
6400 mono_object_get_class (MonoObject *obj)
6402 MONO_REQ_GC_UNSAFE_MODE;
6404 return mono_object_class (obj);
6407 * mono_object_get_size:
6408 * @o: object to query
6410 * Returns: the size, in bytes, of @o
6413 mono_object_get_size (MonoObject* o)
6415 MONO_REQ_GC_UNSAFE_MODE;
6417 MonoClass* klass = mono_object_class (o);
6418 if (klass == mono_defaults.string_class) {
6419 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6420 } else if (o->vtable->rank) {
6421 MonoArray *array = (MonoArray*)o;
6422 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6423 if (array->bounds) {
6426 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6430 return mono_class_instance_size (klass);
6435 * mono_object_unbox:
6436 * @obj: object to unbox
6438 * Returns: a pointer to the start of the valuetype boxed in this
6441 * This method will assert if the object passed is not a valuetype.
6444 mono_object_unbox (MonoObject *obj)
6446 MONO_REQ_GC_UNSAFE_MODE;
6448 /* add assert for valuetypes? */
6449 g_assert (obj->vtable->klass->valuetype);
6450 return ((char*)obj) + sizeof (MonoObject);
6454 * mono_object_isinst:
6456 * @klass: a pointer to a class
6458 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6461 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6463 MONO_REQ_GC_UNSAFE_MODE;
6466 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6467 mono_error_cleanup (&error);
6473 * mono_object_isinst_checked:
6475 * @klass: a pointer to a class
6476 * @error: set on error
6478 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6479 * On failure returns NULL and sets @error.
6482 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6484 MONO_REQ_GC_UNSAFE_MODE;
6486 mono_error_init (error);
6488 MonoObject *result = NULL;
6491 mono_class_init (klass);
6493 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6494 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6501 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6505 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6507 MONO_REQ_GC_UNSAFE_MODE;
6510 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6511 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6516 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6518 MONO_REQ_GC_UNSAFE_MODE;
6522 mono_error_init (error);
6529 if (mono_class_is_interface (klass)) {
6530 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6534 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6535 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6538 MonoClass *oklass = vt->klass;
6539 if (mono_class_is_transparent_proxy (oklass))
6540 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6542 mono_class_setup_supertypes (klass);
6543 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6546 #ifndef DISABLE_REMOTING
6547 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6549 MonoDomain *domain = mono_domain_get ();
6551 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6552 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6553 MonoMethod *im = NULL;
6556 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6558 mono_error_set_not_supported (error, "Linked away.");
6561 im = mono_object_get_virtual_method (rp, im);
6564 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6565 return_val_if_nok (error, NULL);
6568 res = mono_runtime_invoke_checked (im, rp, pa, error);
6569 return_val_if_nok (error, NULL);
6571 if (*(MonoBoolean *) mono_object_unbox(res)) {
6572 /* Update the vtable of the remote type, so it can safely cast to this new type */
6573 mono_upgrade_remote_class (domain, obj, klass, error);
6574 return_val_if_nok (error, NULL);
6578 #endif /* DISABLE_REMOTING */
6583 * mono_object_castclass_mbyref:
6585 * @klass: a pointer to a class
6587 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6590 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6592 MONO_REQ_GC_UNSAFE_MODE;
6595 if (!obj) return NULL;
6596 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6597 mono_error_cleanup (&error);
6602 MonoDomain *orig_domain;
6608 str_lookup (MonoDomain *domain, gpointer user_data)
6610 MONO_REQ_GC_UNSAFE_MODE;
6612 LDStrInfo *info = (LDStrInfo *)user_data;
6613 if (info->res || domain == info->orig_domain)
6615 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6619 mono_string_get_pinned (MonoString *str, MonoError *error)
6621 MONO_REQ_GC_UNSAFE_MODE;
6623 mono_error_init (error);
6625 /* We only need to make a pinned version of a string if this is a moving GC */
6626 if (!mono_gc_is_moving ())
6630 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6631 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6633 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6634 news->length = mono_string_length (str);
6636 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6642 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6644 MONO_REQ_GC_UNSAFE_MODE;
6646 MonoGHashTable *ldstr_table;
6647 MonoString *s, *res;
6650 mono_error_init (error);
6652 domain = ((MonoObject *)str)->vtable->domain;
6653 ldstr_table = domain->ldstr_table;
6655 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6661 /* Allocate outside the lock */
6663 s = mono_string_get_pinned (str, error);
6664 return_val_if_nok (error, NULL);
6667 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6672 mono_g_hash_table_insert (ldstr_table, s, s);
6677 LDStrInfo ldstr_info;
6678 ldstr_info.orig_domain = domain;
6679 ldstr_info.ins = str;
6680 ldstr_info.res = NULL;
6682 mono_domain_foreach (str_lookup, &ldstr_info);
6683 if (ldstr_info.res) {
6685 * the string was already interned in some other domain:
6686 * intern it in the current one as well.
6688 mono_g_hash_table_insert (ldstr_table, str, str);
6698 * mono_string_is_interned:
6699 * @o: String to probe
6701 * Returns whether the string has been interned.
6704 mono_string_is_interned (MonoString *o)
6707 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6708 /* This function does not fail. */
6709 mono_error_assert_ok (&error);
6714 * mono_string_intern:
6715 * @o: String to intern
6717 * Interns the string passed.
6718 * Returns: The interned string.
6721 mono_string_intern (MonoString *str)
6724 MonoString *result = mono_string_intern_checked (str, &error);
6725 mono_error_assert_ok (&error);
6730 * mono_string_intern_checked:
6731 * @o: String to intern
6732 * @error: set on error.
6734 * Interns the string passed.
6735 * Returns: The interned string. On failure returns NULL and sets @error
6738 mono_string_intern_checked (MonoString *str, MonoError *error)
6740 MONO_REQ_GC_UNSAFE_MODE;
6742 mono_error_init (error);
6744 return mono_string_is_interned_lookup (str, TRUE, error);
6749 * @domain: the domain where the string will be used.
6750 * @image: a metadata context
6751 * @idx: index into the user string table.
6753 * Implementation for the ldstr opcode.
6754 * Returns: a loaded string from the @image/@idx combination.
6757 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6760 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6761 mono_error_cleanup (&error);
6766 * mono_ldstr_checked:
6767 * @domain: the domain where the string will be used.
6768 * @image: a metadata context
6769 * @idx: index into the user string table.
6770 * @error: set on error.
6772 * Implementation for the ldstr opcode.
6773 * Returns: a loaded string from the @image/@idx combination.
6774 * On failure returns NULL and sets @error.
6777 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6779 MONO_REQ_GC_UNSAFE_MODE;
6780 mono_error_init (error);
6782 if (image->dynamic) {
6783 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6786 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6787 return NULL; /*FIXME we should probably be raising an exception here*/
6788 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6794 * mono_ldstr_metadata_sig
6795 * @domain: the domain for the string
6796 * @sig: the signature of a metadata string
6797 * @error: set on error
6799 * Returns: a MonoString for a string stored in the metadata. On
6800 * failure returns NULL and sets @error.
6803 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6805 MONO_REQ_GC_UNSAFE_MODE;
6807 mono_error_init (error);
6808 const char *str = sig;
6809 MonoString *o, *interned;
6812 len2 = mono_metadata_decode_blob_size (str, &str);
6815 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6816 return_val_if_nok (error, NULL);
6817 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6820 guint16 *p2 = (guint16*)mono_string_chars (o);
6821 for (i = 0; i < len2; ++i) {
6822 *p2 = GUINT16_FROM_LE (*p2);
6828 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6831 return interned; /* o will get garbage collected */
6833 o = mono_string_get_pinned (o, error);
6836 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6838 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6850 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6854 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6860 GError *gerror = NULL;
6862 mono_error_init (error);
6864 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6865 return NULL; /*FIXME we should probably be raising an exception here*/
6866 str = mono_metadata_user_string (image, idx);
6868 len2 = mono_metadata_decode_blob_size (str, &str);
6871 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6873 mono_error_set_argument (error, "string", "%s", gerror->message);
6874 g_error_free (gerror);
6877 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6878 if (len2 > written) {
6879 /* allocate the total length and copy the part of the string that has been converted */
6880 char *as2 = (char *)g_malloc0 (len2);
6881 memcpy (as2, as, written);
6890 * mono_string_to_utf8:
6891 * @s: a System.String
6893 * Returns the UTF8 representation for @s.
6894 * The resulting buffer needs to be freed with mono_free().
6896 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6899 mono_string_to_utf8 (MonoString *s)
6901 MONO_REQ_GC_UNSAFE_MODE;
6904 char *result = mono_string_to_utf8_checked (s, &error);
6906 if (!is_ok (&error)) {
6907 mono_error_cleanup (&error);
6914 * mono_string_to_utf8_checked:
6915 * @s: a System.String
6916 * @error: a MonoError.
6918 * Converts a MonoString to its UTF8 representation. May fail; check
6919 * @error to determine whether the conversion was successful.
6920 * The resulting buffer should be freed with mono_free().
6923 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6925 MONO_REQ_GC_UNSAFE_MODE;
6929 GError *gerror = NULL;
6931 mono_error_init (error);
6937 return g_strdup ("");
6939 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6941 mono_error_set_argument (error, "string", "%s", gerror->message);
6942 g_error_free (gerror);
6945 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6946 if (s->length > written) {
6947 /* allocate the total length and copy the part of the string that has been converted */
6948 char *as2 = (char *)g_malloc0 (s->length);
6949 memcpy (as2, as, written);
6958 * mono_string_to_utf8_ignore:
6961 * Converts a MonoString to its UTF8 representation. Will ignore
6962 * invalid surrogate pairs.
6963 * The resulting buffer should be freed with mono_free().
6967 mono_string_to_utf8_ignore (MonoString *s)
6969 MONO_REQ_GC_UNSAFE_MODE;
6978 return g_strdup ("");
6980 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6982 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6983 if (s->length > written) {
6984 /* allocate the total length and copy the part of the string that has been converted */
6985 char *as2 = (char *)g_malloc0 (s->length);
6986 memcpy (as2, as, written);
6995 * mono_string_to_utf8_image_ignore:
6996 * @s: a System.String
6998 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7001 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7003 MONO_REQ_GC_UNSAFE_MODE;
7005 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7009 * mono_string_to_utf8_mp_ignore:
7010 * @s: a System.String
7012 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7015 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7017 MONO_REQ_GC_UNSAFE_MODE;
7019 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7024 * mono_string_to_utf16:
7027 * Return an null-terminated array of the utf-16 chars
7028 * contained in @s. The result must be freed with g_free().
7029 * This is a temporary helper until our string implementation
7030 * is reworked to always include the null terminating char.
7033 mono_string_to_utf16 (MonoString *s)
7035 MONO_REQ_GC_UNSAFE_MODE;
7042 as = (char *)g_malloc ((s->length * 2) + 2);
7043 as [(s->length * 2)] = '\0';
7044 as [(s->length * 2) + 1] = '\0';
7047 return (gunichar2 *)(as);
7050 memcpy (as, mono_string_chars(s), s->length * 2);
7051 return (gunichar2 *)(as);
7055 * mono_string_to_utf32:
7058 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7059 * contained in @s. The result must be freed with g_free().
7062 mono_string_to_utf32 (MonoString *s)
7064 MONO_REQ_GC_UNSAFE_MODE;
7066 mono_unichar4 *utf32_output = NULL;
7067 GError *error = NULL;
7068 glong items_written;
7073 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7076 g_error_free (error);
7078 return utf32_output;
7082 * mono_string_from_utf16:
7083 * @data: the UTF16 string (LPWSTR) to convert
7085 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7087 * Returns: a MonoString.
7090 mono_string_from_utf16 (gunichar2 *data)
7093 MonoString *result = mono_string_from_utf16_checked (data, &error);
7094 mono_error_cleanup (&error);
7099 * mono_string_from_utf16_checked:
7100 * @data: the UTF16 string (LPWSTR) to convert
7101 * @error: set on error
7103 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7105 * Returns: a MonoString. On failure sets @error and returns NULL.
7108 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7111 MONO_REQ_GC_UNSAFE_MODE;
7113 mono_error_init (error);
7114 MonoDomain *domain = mono_domain_get ();
7120 while (data [len]) len++;
7122 return mono_string_new_utf16_checked (domain, data, len, error);
7126 * mono_string_from_utf32:
7127 * @data: the UTF32 string (LPWSTR) to convert
7129 * Converts a UTF32 (UCS-4)to a MonoString.
7131 * Returns: a MonoString.
7134 mono_string_from_utf32 (mono_unichar4 *data)
7137 MonoString *result = mono_string_from_utf32_checked (data, &error);
7138 mono_error_cleanup (&error);
7143 * mono_string_from_utf32_checked:
7144 * @data: the UTF32 string (LPWSTR) to convert
7145 * @error: set on error
7147 * Converts a UTF32 (UCS-4)to a MonoString.
7149 * Returns: a MonoString. On failure returns NULL and sets @error.
7152 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7154 MONO_REQ_GC_UNSAFE_MODE;
7156 mono_error_init (error);
7157 MonoString* result = NULL;
7158 mono_unichar2 *utf16_output = NULL;
7159 GError *gerror = NULL;
7160 glong items_written;
7166 while (data [len]) len++;
7168 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7171 g_error_free (gerror);
7173 result = mono_string_from_utf16_checked (utf16_output, error);
7174 g_free (utf16_output);
7179 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7181 MONO_REQ_GC_UNSAFE_MODE;
7188 r = mono_string_to_utf8_ignore (s);
7190 r = mono_string_to_utf8_checked (s, error);
7191 if (!mono_error_ok (error))
7198 len = strlen (r) + 1;
7200 mp_s = (char *)mono_mempool_alloc (mp, len);
7202 mp_s = (char *)mono_image_alloc (image, len);
7204 memcpy (mp_s, r, len);
7212 * mono_string_to_utf8_image:
7213 * @s: a System.String
7215 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7218 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7220 MONO_REQ_GC_UNSAFE_MODE;
7222 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7226 * mono_string_to_utf8_mp:
7227 * @s: a System.String
7229 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7232 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7234 MONO_REQ_GC_UNSAFE_MODE;
7236 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7240 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7243 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7245 eh_callbacks = *cbs;
7248 MonoRuntimeExceptionHandlingCallbacks *
7249 mono_get_eh_callbacks (void)
7251 return &eh_callbacks;
7255 * mono_raise_exception:
7256 * @ex: exception object
7258 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7261 mono_raise_exception (MonoException *ex)
7263 MONO_REQ_GC_UNSAFE_MODE;
7266 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7267 * that will cause gcc to omit the function epilog, causing problems when
7268 * the JIT tries to walk the stack, since the return address on the stack
7269 * will point into the next function in the executable, not this one.
7271 eh_callbacks.mono_raise_exception (ex);
7275 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7277 MONO_REQ_GC_UNSAFE_MODE;
7279 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7283 * mono_wait_handle_new:
7284 * @domain: Domain where the object will be created
7285 * @handle: Handle for the wait handle
7286 * @error: set on error.
7288 * Returns: A new MonoWaitHandle created in the given domain for the
7289 * given handle. On failure returns NULL and sets @rror.
7292 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7294 MONO_REQ_GC_UNSAFE_MODE;
7296 MonoWaitHandle *res;
7297 gpointer params [1];
7298 static MonoMethod *handle_set;
7300 mono_error_init (error);
7301 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7302 return_val_if_nok (error, NULL);
7304 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7306 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7308 params [0] = &handle;
7310 mono_runtime_invoke_checked (handle_set, res, params, error);
7315 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7317 MONO_REQ_GC_UNSAFE_MODE;
7319 static MonoClassField *f_safe_handle = NULL;
7322 if (!f_safe_handle) {
7323 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7324 g_assert (f_safe_handle);
7327 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7333 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7335 MONO_REQ_GC_UNSAFE_MODE;
7337 RuntimeInvokeFunction runtime_invoke;
7339 mono_error_init (error);
7341 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7342 MonoMethod *method = mono_get_context_capture_method ();
7343 MonoMethod *wrapper;
7346 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7347 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7348 return_val_if_nok (error, NULL);
7349 domain->capture_context_method = mono_compile_method_checked (method, error);
7350 return_val_if_nok (error, NULL);
7353 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7355 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7358 * mono_async_result_new:
7359 * @domain:domain where the object will be created.
7360 * @handle: wait handle.
7361 * @state: state to pass to AsyncResult
7362 * @data: C closure data.
7363 * @error: set on error.
7365 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7366 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7367 * On failure returns NULL and sets @error.
7371 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7373 MONO_REQ_GC_UNSAFE_MODE;
7375 mono_error_init (error);
7376 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7377 return_val_if_nok (error, NULL);
7378 MonoObject *context = mono_runtime_capture_context (domain, error);
7379 return_val_if_nok (error, NULL);
7380 /* we must capture the execution context from the original thread */
7382 MONO_OBJECT_SETREF (res, execution_context, context);
7383 /* note: result may be null if the flow is suppressed */
7386 res->data = (void **)data;
7387 MONO_OBJECT_SETREF (res, object_data, object_data);
7388 MONO_OBJECT_SETREF (res, async_state, state);
7389 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7390 return_val_if_nok (error, NULL);
7392 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7394 res->sync_completed = FALSE;
7395 res->completed = FALSE;
7401 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7403 MONO_REQ_GC_UNSAFE_MODE;
7410 g_assert (ares->async_delegate);
7412 ac = (MonoAsyncCall*) ares->object_data;
7414 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7415 if (mono_error_set_pending_exception (&error))
7418 gpointer wait_event = NULL;
7420 ac->msg->exc = NULL;
7422 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7424 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7425 mono_threads_begin_abort_protected_block ();
7427 if (!ac->msg->exc) {
7428 MonoException *ex = mono_error_convert_to_exception (&error);
7429 ac->msg->exc = (MonoObject *)ex;
7431 mono_error_cleanup (&error);
7434 MONO_OBJECT_SETREF (ac, res, res);
7436 mono_monitor_enter ((MonoObject*) ares);
7437 ares->completed = 1;
7439 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7440 mono_monitor_exit ((MonoObject*) ares);
7442 if (wait_event != NULL)
7443 mono_w32event_set (wait_event);
7445 mono_error_init (&error); //the else branch would leave it in an undefined state
7447 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7449 mono_threads_end_abort_protected_block ();
7451 if (mono_error_set_pending_exception (&error))
7459 mono_message_init (MonoDomain *domain,
7460 MonoMethodMessage *this_obj,
7461 MonoReflectionMethod *method,
7462 MonoArray *out_args,
7465 MONO_REQ_GC_UNSAFE_MODE;
7467 static MonoMethod *init_message_method = NULL;
7469 if (!init_message_method) {
7470 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7471 g_assert (init_message_method != NULL);
7474 mono_error_init (error);
7475 /* FIXME set domain instead? */
7476 g_assert (domain == mono_domain_get ());
7483 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7484 return is_ok (error);
7487 #ifndef DISABLE_REMOTING
7489 * mono_remoting_invoke:
7490 * @real_proxy: pointer to a RealProxy object
7491 * @msg: The MonoMethodMessage to execute
7492 * @exc: used to store exceptions
7493 * @out_args: used to store output arguments
7495 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7496 * IMessage interface and it is not trivial to extract results from there. So
7497 * we call an helper method PrivateInvoke instead of calling
7498 * RealProxy::Invoke() directly.
7500 * Returns: the result object.
7503 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7505 MONO_REQ_GC_UNSAFE_MODE;
7508 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7513 mono_error_init (error);
7515 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7518 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7520 mono_error_set_not_supported (error, "Linked away.");
7523 real_proxy->vtable->domain->private_invoke_method = im;
7526 pa [0] = real_proxy;
7531 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7532 return_val_if_nok (error, NULL);
7539 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7540 MonoObject **exc, MonoArray **out_args, MonoError *error)
7542 MONO_REQ_GC_UNSAFE_MODE;
7544 static MonoClass *object_array_klass;
7545 mono_error_init (error);
7549 MonoMethodSignature *sig;
7551 int i, j, outarg_count = 0;
7553 #ifndef DISABLE_REMOTING
7554 if (target && mono_object_is_transparent_proxy (target)) {
7555 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7556 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7557 target = tp->rp->unwrapped_server;
7559 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7564 domain = mono_domain_get ();
7565 method = msg->method->method;
7566 sig = mono_method_signature (method);
7568 for (i = 0; i < sig->param_count; i++) {
7569 if (sig->params [i]->byref)
7573 if (!object_array_klass) {
7576 klass = mono_array_class_get (mono_defaults.object_class, 1);
7579 mono_memory_barrier ();
7580 object_array_klass = klass;
7583 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7584 return_val_if_nok (error, NULL);
7586 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7589 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7590 return_val_if_nok (error, NULL);
7592 for (i = 0, j = 0; i < sig->param_count; i++) {
7593 if (sig->params [i]->byref) {
7595 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7596 mono_array_setref (*out_args, j, arg);
7605 * prepare_to_string_method:
7607 * @target: Set to @obj or unboxed value if a valuetype
7609 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7612 prepare_to_string_method (MonoObject *obj, void **target)
7614 MONO_REQ_GC_UNSAFE_MODE;
7616 static MonoMethod *to_string = NULL;
7624 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7626 method = mono_object_get_virtual_method (obj, to_string);
7628 // Unbox value type if needed
7629 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7630 *target = mono_object_unbox (obj);
7636 * mono_object_to_string:
7638 * @exc: Any exception thrown by ToString (). May be NULL.
7640 * Returns: the result of calling ToString () on an object.
7643 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7646 MonoString *s = NULL;
7648 MonoMethod *method = prepare_to_string_method (obj, &target);
7650 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7651 if (*exc == NULL && !mono_error_ok (&error))
7652 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7654 mono_error_cleanup (&error);
7656 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7657 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7664 * mono_object_to_string_checked:
7666 * @error: Set on error.
7668 * Returns: the result of calling ToString () on an object. If the
7669 * method cannot be invoked or if it raises an exception, sets @error
7673 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7675 mono_error_init (error);
7677 MonoMethod *method = prepare_to_string_method (obj, &target);
7678 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7682 * mono_object_try_to_string:
7684 * @exc: Any exception thrown by ToString (). Must not be NULL.
7685 * @error: Set if method cannot be invoked.
7687 * Returns: the result of calling ToString () on an object. If the
7688 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7692 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7695 mono_error_init (error);
7697 MonoMethod *method = prepare_to_string_method (obj, &target);
7698 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7704 * mono_print_unhandled_exception:
7705 * @exc: The exception
7707 * Prints the unhandled exception.
7710 mono_print_unhandled_exception (MonoObject *exc)
7712 MONO_REQ_GC_UNSAFE_MODE;
7715 char *message = (char*)"";
7716 gboolean free_message = FALSE;
7719 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7720 message = g_strdup ("OutOfMemoryException");
7721 free_message = TRUE;
7722 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7723 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7724 free_message = TRUE;
7727 if (((MonoException*)exc)->native_trace_ips) {
7728 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7729 free_message = TRUE;
7731 MonoObject *other_exc = NULL;
7732 str = mono_object_try_to_string (exc, &other_exc, &error);
7733 if (other_exc == NULL && !is_ok (&error))
7734 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7736 mono_error_cleanup (&error);
7738 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7739 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7741 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7742 original_backtrace, nested_backtrace);
7744 g_free (original_backtrace);
7745 g_free (nested_backtrace);
7746 free_message = TRUE;
7748 message = mono_string_to_utf8_checked (str, &error);
7749 if (!mono_error_ok (&error)) {
7750 mono_error_cleanup (&error);
7751 message = (char *) "";
7753 free_message = TRUE;
7760 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7761 * exc->vtable->klass->name, message);
7763 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7770 * mono_delegate_ctor_with_method:
7771 * @this: pointer to an uninitialized delegate object
7772 * @target: target object
7773 * @addr: pointer to native code
7775 * @error: set on error.
7777 * Initialize a delegate and sets a specific method, not the one
7778 * associated with addr. This is useful when sharing generic code.
7779 * In that case addr will most probably not be associated with the
7780 * correct instantiation of the method.
7781 * On failure returns FALSE and sets @error.
7784 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7786 MONO_REQ_GC_UNSAFE_MODE;
7788 mono_error_init (error);
7789 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7791 g_assert (this_obj);
7794 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7797 delegate->method = method;
7799 mono_stats.delegate_creations++;
7801 #ifndef DISABLE_REMOTING
7802 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7804 method = mono_marshal_get_remoting_invoke (method);
7805 delegate->method_ptr = mono_compile_method_checked (method, error);
7806 return_val_if_nok (error, FALSE);
7807 MONO_OBJECT_SETREF (delegate, target, target);
7811 delegate->method_ptr = addr;
7812 MONO_OBJECT_SETREF (delegate, target, target);
7815 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7816 if (callbacks.init_delegate)
7817 callbacks.init_delegate (delegate);
7822 * mono_delegate_ctor:
7823 * @this: pointer to an uninitialized delegate object
7824 * @target: target object
7825 * @addr: pointer to native code
7826 * @error: set on error.
7828 * This is used to initialize a delegate.
7829 * On failure returns FALSE and sets @error.
7832 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7834 MONO_REQ_GC_UNSAFE_MODE;
7836 mono_error_init (error);
7837 MonoDomain *domain = mono_domain_get ();
7839 MonoMethod *method = NULL;
7843 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7845 if (!ji && domain != mono_get_root_domain ())
7846 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7848 method = mono_jit_info_get_method (ji);
7849 g_assert (!mono_class_is_gtd (method->klass));
7852 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7856 * mono_method_call_message_new:
7857 * @method: method to encapsulate
7858 * @params: parameters to the method
7859 * @invoke: optional, delegate invoke.
7860 * @cb: async callback delegate.
7861 * @state: state passed to the async callback.
7862 * @error: set on error.
7864 * Translates arguments pointers into a MonoMethodMessage.
7865 * On failure returns NULL and sets @error.
7868 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7869 MonoDelegate **cb, MonoObject **state, MonoError *error)
7871 MONO_REQ_GC_UNSAFE_MODE;
7873 mono_error_init (error);
7875 MonoDomain *domain = mono_domain_get ();
7876 MonoMethodSignature *sig = mono_method_signature (method);
7877 MonoMethodMessage *msg;
7880 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7881 return_val_if_nok (error, NULL);
7884 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7885 return_val_if_nok (error, NULL);
7886 mono_message_init (domain, msg, rm, NULL, error);
7887 return_val_if_nok (error, NULL);
7888 count = sig->param_count - 2;
7890 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7891 return_val_if_nok (error, NULL);
7892 mono_message_init (domain, msg, rm, NULL, error);
7893 return_val_if_nok (error, NULL);
7894 count = sig->param_count;
7897 for (i = 0; i < count; i++) {
7902 if (sig->params [i]->byref)
7903 vpos = *((gpointer *)params [i]);
7907 klass = mono_class_from_mono_type (sig->params [i]);
7909 if (klass->valuetype) {
7910 arg = mono_value_box_checked (domain, klass, vpos, error);
7911 return_val_if_nok (error, NULL);
7913 arg = *((MonoObject **)vpos);
7915 mono_array_setref (msg->args, i, arg);
7918 if (cb != NULL && state != NULL) {
7919 *cb = *((MonoDelegate **)params [i]);
7921 *state = *((MonoObject **)params [i]);
7928 * mono_method_return_message_restore:
7930 * Restore results from message based processing back to arguments pointers
7933 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7935 MONO_REQ_GC_UNSAFE_MODE;
7937 mono_error_init (error);
7939 MonoMethodSignature *sig = mono_method_signature (method);
7940 int i, j, type, size, out_len;
7942 if (out_args == NULL)
7944 out_len = mono_array_length (out_args);
7948 for (i = 0, j = 0; i < sig->param_count; i++) {
7949 MonoType *pt = sig->params [i];
7954 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7958 arg = (char *)mono_array_get (out_args, gpointer, j);
7961 g_assert (type != MONO_TYPE_VOID);
7963 if (MONO_TYPE_IS_REFERENCE (pt)) {
7964 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7967 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7968 size = mono_class_value_size (klass, NULL);
7969 if (klass->has_references)
7970 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7972 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7974 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7975 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7984 #ifndef DISABLE_REMOTING
7987 * mono_load_remote_field:
7988 * @this: pointer to an object
7989 * @klass: klass of the object containing @field
7990 * @field: the field to load
7991 * @res: a storage to store the result
7993 * This method is called by the runtime on attempts to load fields of
7994 * transparent proxy objects. @this points to such TP, @klass is the class of
7995 * the object containing @field. @res is a storage location which can be
7996 * used to store the result.
7998 * Returns: an address pointing to the value of field.
8001 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8004 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8005 mono_error_cleanup (&error);
8010 * mono_load_remote_field_checked:
8011 * @this: pointer to an object
8012 * @klass: klass of the object containing @field
8013 * @field: the field to load
8014 * @res: a storage to store the result
8015 * @error: set on error
8017 * This method is called by the runtime on attempts to load fields of
8018 * transparent proxy objects. @this points to such TP, @klass is the class of
8019 * the object containing @field. @res is a storage location which can be
8020 * used to store the result.
8022 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8025 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8027 MONO_REQ_GC_UNSAFE_MODE;
8029 static MonoMethod *getter = NULL;
8031 mono_error_init (error);
8033 MonoDomain *domain = mono_domain_get ();
8034 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8035 MonoClass *field_class;
8036 MonoMethodMessage *msg;
8037 MonoArray *out_args;
8041 g_assert (mono_object_is_transparent_proxy (this_obj));
8042 g_assert (res != NULL);
8044 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8045 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8050 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8052 mono_error_set_not_supported (error, "Linked away.");
8057 field_class = mono_class_from_mono_type (field->type);
8059 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8060 return_val_if_nok (error, NULL);
8061 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8062 return_val_if_nok (error, NULL);
8063 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8064 return_val_if_nok (error, NULL);
8065 mono_message_init (domain, msg, rm, out_args, error);
8066 return_val_if_nok (error, NULL);
8068 full_name = mono_type_get_full_name (klass);
8069 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8070 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8073 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8074 return_val_if_nok (error, NULL);
8077 mono_error_set_exception_instance (error, (MonoException *)exc);
8081 if (mono_array_length (out_args) == 0)
8084 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8086 if (field_class->valuetype) {
8087 return ((char *)*res) + sizeof (MonoObject);
8093 * mono_load_remote_field_new:
8098 * Missing documentation.
8101 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8105 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8106 mono_error_cleanup (&error);
8111 * mono_load_remote_field_new_checked:
8112 * @this: pointer to an object
8113 * @klass: klass of the object containing @field
8114 * @field: the field to load
8115 * @error: set on error.
8117 * This method is called by the runtime on attempts to load fields of
8118 * transparent proxy objects. @this points to such TP, @klass is the class of
8119 * the object containing @field.
8121 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8124 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8126 MONO_REQ_GC_UNSAFE_MODE;
8128 mono_error_init (error);
8130 static MonoMethod *tp_load = NULL;
8132 g_assert (mono_object_is_transparent_proxy (this_obj));
8135 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8137 mono_error_set_not_supported (error, "Linked away.");
8142 /* MonoType *type = mono_class_get_type (klass); */
8148 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8152 * mono_store_remote_field:
8153 * @this_obj: pointer to an object
8154 * @klass: klass of the object containing @field
8155 * @field: the field to load
8156 * @val: the value/object to store
8158 * This method is called by the runtime on attempts to store fields of
8159 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8160 * the object containing @field. @val is the new value to store in @field.
8163 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8166 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8167 mono_error_cleanup (&error);
8171 * mono_store_remote_field_checked:
8172 * @this_obj: pointer to an object
8173 * @klass: klass of the object containing @field
8174 * @field: the field to load
8175 * @val: the value/object to store
8176 * @error: set on error
8178 * This method is called by the runtime on attempts to store fields of
8179 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8180 * the object containing @field. @val is the new value to store in @field.
8182 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8185 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8188 MONO_REQ_GC_UNSAFE_MODE;
8190 mono_error_init (error);
8192 MonoDomain *domain = mono_domain_get ();
8193 MonoClass *field_class;
8196 g_assert (mono_object_is_transparent_proxy (this_obj));
8198 field_class = mono_class_from_mono_type (field->type);
8200 if (field_class->valuetype) {
8201 arg = mono_value_box_checked (domain, field_class, val, error);
8202 return_val_if_nok (error, FALSE);
8204 arg = *((MonoObject**)val);
8207 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8211 * mono_store_remote_field_new:
8217 * Missing documentation
8220 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8223 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8224 mono_error_cleanup (&error);
8228 * mono_store_remote_field_new_checked:
8235 * Missing documentation
8238 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8240 MONO_REQ_GC_UNSAFE_MODE;
8242 static MonoMethod *tp_store = NULL;
8244 mono_error_init (error);
8246 g_assert (mono_object_is_transparent_proxy (this_obj));
8249 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8251 mono_error_set_not_supported (error, "Linked away.");
8261 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8262 return is_ok (error);
8267 * mono_create_ftnptr:
8269 * Given a function address, create a function descriptor for it.
8270 * This is only needed on some platforms.
8273 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8275 return callbacks.create_ftnptr (domain, addr);
8279 * mono_get_addr_from_ftnptr:
8281 * Given a pointer to a function descriptor, return the function address.
8282 * This is only needed on some platforms.
8285 mono_get_addr_from_ftnptr (gpointer descr)
8287 return callbacks.get_addr_from_ftnptr (descr);
8291 * mono_string_chars:
8294 * Returns a pointer to the UCS16 characters stored in the MonoString
8297 mono_string_chars (MonoString *s)
8299 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8305 * mono_string_length:
8308 * Returns the lenght in characters of the string
8311 mono_string_length (MonoString *s)
8313 MONO_REQ_GC_UNSAFE_MODE;
8319 * mono_array_length:
8320 * @array: a MonoArray*
8322 * Returns the total number of elements in the array. This works for
8323 * both vectors and multidimensional arrays.
8326 mono_array_length (MonoArray *array)
8328 MONO_REQ_GC_UNSAFE_MODE;
8330 return array->max_length;
8334 * mono_array_addr_with_size:
8335 * @array: a MonoArray*
8336 * @size: size of the array elements
8337 * @idx: index into the array
8339 * Use this function to obtain the address for the @idx item on the
8340 * @array containing elements of size @size.
8342 * This method performs no bounds checking or type checking.
8344 * Returns the address of the @idx element in the array.
8347 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8349 MONO_REQ_GC_UNSAFE_MODE;
8351 return ((char*)(array)->vector) + size * idx;
8356 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8358 MonoDomain *domain = mono_domain_get ();
8362 mono_error_init (error);
8366 len = g_list_length (list);
8367 res = mono_array_new_checked (domain, eclass, len, error);
8368 return_val_if_nok (error, NULL);
8370 for (i = 0; list; list = list->next, i++)
8371 mono_array_set (res, gpointer, i, list->data);
8378 * The following section is purely to declare prototypes and
8379 * document the API, as these C files are processed by our
8385 * @array: array to alter
8386 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8387 * @index: index into the array
8388 * @value: value to set
8390 * Value Type version: This sets the @index's element of the @array
8391 * with elements of size sizeof(type) to the provided @value.
8393 * This macro does not attempt to perform type checking or bounds checking.
8395 * Use this to set value types in a `MonoArray`.
8397 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8402 * mono_array_setref:
8403 * @array: array to alter
8404 * @index: index into the array
8405 * @value: value to set
8407 * Reference Type version: This sets the @index's element of the
8408 * @array with elements of size sizeof(type) to the provided @value.
8410 * This macro does not attempt to perform type checking or bounds checking.
8412 * Use this to reference types in a `MonoArray`.
8414 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8420 * @array: array on which to operate on
8421 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8422 * @index: index into the array
8424 * Use this macro to retrieve the @index element of an @array and
8425 * extract the value assuming that the elements of the array match
8426 * the provided type value.
8428 * This method can be used with both arrays holding value types and
8429 * reference types. For reference types, the @type parameter should
8430 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8432 * This macro does not attempt to perform type checking or bounds checking.
8434 * Returns: The element at the @index position in the @array.
8436 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)