3 * Object creation for the Mono runtime
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.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/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include <mono/utils/mono-threads-coop.h>
50 #include "cominterop.h"
51 #include <mono/utils/w32api.h>
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
66 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
69 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
71 /* Class lazy loading functions */
72 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
73 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
74 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
75 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
76 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
79 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
80 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
81 static mono_mutex_t ldstr_section;
85 * mono_runtime_object_init:
86 * \param this_obj the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
91 mono_runtime_object_init (MonoObject *this_obj)
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
99 * mono_runtime_object_init_checked:
100 * \param this_obj the object to initialize
101 * \param error set on error.
102 * This function calls the zero-argument constructor (which must
103 * exist) for the given object and returns TRUE on success, or FALSE
104 * on error and sets \p error.
107 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
109 MONO_REQ_GC_UNSAFE_MODE;
111 MonoMethod *method = NULL;
112 MonoClass *klass = this_obj->vtable->klass;
115 method = mono_class_get_method_from_name (klass, ".ctor", 0);
117 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
119 if (method->klass->valuetype)
120 this_obj = (MonoObject *)mono_object_unbox (this_obj);
122 mono_runtime_invoke_checked (method, this_obj, NULL, error);
123 return is_ok (error);
126 /* The pseudo algorithm for type initialization from the spec
127 Note it doesn't say anything about domains - only threads.
129 2. If the type is initialized you are done.
130 2.1. If the type is not yet initialized, try to take an
132 2.2. If successful, record this thread as responsible for
133 initializing the type and proceed to step 2.3.
134 2.2.1. If not, see whether this thread or any thread
135 waiting for this thread to complete already holds the lock.
136 2.2.2. If so, return since blocking would create a deadlock. This thread
137 will now see an incompletely initialized state for the type,
138 but no deadlock will arise.
139 2.2.3 If not, block until the type is initialized then return.
140 2.3 Initialize the parent type and then all interfaces implemented
142 2.4 Execute the type initialization code for this type.
143 2.5 Mark the type as initialized, release the initialization lock,
144 awaken any threads waiting for this type to be initialized,
151 MonoNativeThreadId initializing_tid;
152 guint32 waiting_count;
155 /* condvar used to wait for 'done' becoming TRUE */
157 } TypeInitializationLock;
159 /* for locking access to type_initialization_hash and blocked_thread_hash */
160 static MonoCoopMutex type_initialization_section;
163 mono_type_initialization_lock (void)
165 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
166 mono_coop_mutex_lock (&type_initialization_section);
170 mono_type_initialization_unlock (void)
172 mono_coop_mutex_unlock (&type_initialization_section);
176 mono_type_init_lock (TypeInitializationLock *lock)
178 MONO_REQ_GC_NEUTRAL_MODE;
180 mono_coop_mutex_lock (&lock->mutex);
184 mono_type_init_unlock (TypeInitializationLock *lock)
186 mono_coop_mutex_unlock (&lock->mutex);
189 /* from vtable to lock */
190 static GHashTable *type_initialization_hash;
192 /* from thread id to thread id being waited on */
193 static GHashTable *blocked_thread_hash;
196 static MonoThread *main_thread;
198 /* Functions supplied by the runtime */
199 static MonoRuntimeCallbacks callbacks;
202 * mono_thread_set_main:
203 * \param thread thread to set as the main thread
204 * This function can be used to instruct the runtime to treat \p thread
205 * as the main thread, ie, the thread that would normally execute the Main()
206 * method. This basically means that at the end of \p thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 main_thread = thread;
225 mono_thread_get_main (void)
227 MONO_REQ_GC_UNSAFE_MODE;
233 mono_type_initialization_init (void)
235 mono_coop_mutex_init_recursive (&type_initialization_section);
236 type_initialization_hash = g_hash_table_new (NULL, NULL);
237 blocked_thread_hash = g_hash_table_new (NULL, NULL);
238 mono_os_mutex_init_recursive (&ldstr_section);
242 mono_type_initialization_cleanup (void)
245 /* This is causing race conditions with
246 * mono_release_type_locks
248 mono_coop_mutex_destroy (&type_initialization_section);
249 g_hash_table_destroy (type_initialization_hash);
250 type_initialization_hash = NULL;
252 mono_os_mutex_destroy (&ldstr_section);
253 g_hash_table_destroy (blocked_thread_hash);
254 blocked_thread_hash = NULL;
260 * get_type_init_exception_for_vtable:
262 * Return the stored type initialization exception for VTABLE.
264 static MonoException*
265 get_type_init_exception_for_vtable (MonoVTable *vtable)
267 MONO_REQ_GC_UNSAFE_MODE;
270 MonoDomain *domain = vtable->domain;
271 MonoClass *klass = vtable->klass;
275 if (!vtable->init_failed)
276 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
279 * If the initializing thread was rudely aborted, the exception is not stored
283 mono_domain_lock (domain);
284 if (domain->type_init_exception_hash)
285 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
286 mono_domain_unlock (domain);
289 if (klass->name_space && *klass->name_space)
290 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
292 full_name = g_strdup (klass->name);
293 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
295 return_val_if_nok (&error, NULL);
302 * mono_runtime_class_init:
303 * @vtable: vtable that needs to be initialized
305 * This routine calls the class constructor for @vtable.
308 mono_runtime_class_init (MonoVTable *vtable)
310 MONO_REQ_GC_UNSAFE_MODE;
313 mono_runtime_class_init_full (vtable, &error);
314 mono_error_assert_ok (&error);
318 * Returns TRUE if the lock was freed.
319 * LOCKING: Caller should hold type_initialization_lock.
322 unref_type_lock (TypeInitializationLock *lock)
324 --lock->waiting_count;
325 if (lock->waiting_count == 0) {
326 mono_coop_mutex_destroy (&lock->mutex);
327 mono_coop_cond_destroy (&lock->cond);
336 * mono_runtime_class_init_full:
337 * \param vtable that neeeds to be initialized
338 * \param error set on error
339 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
342 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
344 MONO_REQ_GC_UNSAFE_MODE;
346 MonoMethod *method = NULL;
349 MonoDomain *domain = vtable->domain;
350 TypeInitializationLock *lock;
351 MonoNativeThreadId tid;
352 int do_initialization = 0;
353 MonoDomain *last_domain = NULL;
354 gboolean pending_tae = FALSE;
358 if (vtable->initialized)
361 klass = vtable->klass;
363 if (!klass->image->checked_module_cctor) {
364 mono_image_check_for_module_cctor (klass->image);
365 if (klass->image->has_module_cctor) {
366 MonoClass *module_klass;
367 MonoVTable *module_vtable;
369 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
374 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
377 if (!mono_runtime_class_init_full (module_vtable, error))
381 method = mono_class_get_cctor (klass);
383 vtable->initialized = 1;
387 tid = mono_native_thread_id_get ();
390 * Due some preprocessing inside a global lock. If we are the first thread
391 * trying to initialize this class, create a separate lock+cond var, and
392 * acquire it before leaving the global lock. The other threads will wait
396 mono_type_initialization_lock ();
397 /* double check... */
398 if (vtable->initialized) {
399 mono_type_initialization_unlock ();
402 if (vtable->init_failed) {
403 mono_type_initialization_unlock ();
405 /* The type initialization already failed once, rethrow the same exception */
406 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
409 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
411 /* This thread will get to do the initialization */
412 if (mono_domain_get () != domain) {
413 /* Transfer into the target domain */
414 last_domain = mono_domain_get ();
415 if (!mono_domain_set (domain, FALSE)) {
416 vtable->initialized = 1;
417 mono_type_initialization_unlock ();
418 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
422 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
423 mono_coop_mutex_init_recursive (&lock->mutex);
424 mono_coop_cond_init (&lock->cond);
425 lock->initializing_tid = tid;
426 lock->waiting_count = 1;
428 g_hash_table_insert (type_initialization_hash, vtable, lock);
429 do_initialization = 1;
432 TypeInitializationLock *pending_lock;
434 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
435 mono_type_initialization_unlock ();
438 /* see if the thread doing the initialization is already blocked on this thread */
439 gboolean is_blocked = TRUE;
440 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
441 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
442 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
443 if (!pending_lock->done) {
444 mono_type_initialization_unlock ();
447 /* the thread doing the initialization is blocked on this thread,
448 but on a lock that has already been freed. It just hasn't got
454 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
456 ++lock->waiting_count;
457 /* record the fact that we are waiting on the initializing thread */
459 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
461 mono_type_initialization_unlock ();
463 if (do_initialization) {
464 MonoException *exc = NULL;
466 /* We are holding the per-vtable lock, do the actual initialization */
468 mono_threads_begin_abort_protected_block ();
469 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
470 mono_threads_end_abort_protected_block ();
472 //exception extracted, error will be set to the right value later
473 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
474 exc = mono_error_convert_to_exception (error);
476 mono_error_cleanup (error);
480 /* If the initialization failed, mark the class as unusable. */
481 /* Avoid infinite loops */
483 (klass->image == mono_defaults.corlib &&
484 !strcmp (klass->name_space, "System") &&
485 !strcmp (klass->name, "TypeInitializationException")))) {
486 vtable->init_failed = 1;
488 if (klass->name_space && *klass->name_space)
489 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
491 full_name = g_strdup (klass->name);
493 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
496 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
499 * Store the exception object so it could be thrown on subsequent
502 mono_domain_lock (domain);
503 if (!domain->type_init_exception_hash)
504 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");
505 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
506 mono_domain_unlock (domain);
510 mono_domain_set (last_domain, TRUE);
512 /* Signal to the other threads that we are done */
513 mono_type_init_lock (lock);
515 mono_coop_cond_broadcast (&lock->cond);
516 mono_type_init_unlock (lock);
519 * This can happen if the cctor self-aborts. We need to reactivate tae
520 * (next interruption checkpoint will throw it) and make sure we won't
521 * throw tie for the type.
523 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
525 mono_thread_resume_interruption (FALSE);
528 /* this just blocks until the initializing thread is done */
529 mono_type_init_lock (lock);
531 mono_coop_cond_wait (&lock->cond, &lock->mutex);
532 mono_type_init_unlock (lock);
535 /* Do cleanup and setting vtable->initialized inside the global lock again */
536 mono_type_initialization_lock ();
537 if (!do_initialization)
538 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
539 gboolean deleted = unref_type_lock (lock);
541 g_hash_table_remove (type_initialization_hash, vtable);
542 /* Have to set this here since we check it inside the global lock */
543 if (do_initialization && !vtable->init_failed)
544 vtable->initialized = 1;
545 mono_type_initialization_unlock ();
547 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
548 if (vtable->init_failed && !pending_tae) {
549 /* Either we were the initializing thread or we waited for the initialization */
550 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
557 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
559 MONO_REQ_GC_NEUTRAL_MODE;
561 MonoVTable *vtable = (MonoVTable*)key;
563 TypeInitializationLock *lock = (TypeInitializationLock*) value;
564 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
567 * Have to set this since it cannot be set by the normal code in
568 * mono_runtime_class_init (). In this case, the exception object is not stored,
569 * and get_type_init_exception_for_class () needs to be aware of this.
571 mono_type_init_lock (lock);
572 vtable->init_failed = 1;
573 mono_coop_cond_broadcast (&lock->cond);
574 mono_type_init_unlock (lock);
575 gboolean deleted = unref_type_lock (lock);
583 mono_release_type_locks (MonoInternalThread *thread)
585 MONO_REQ_GC_UNSAFE_MODE;
587 mono_type_initialization_lock ();
588 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
589 mono_type_initialization_unlock ();
592 #ifndef DISABLE_REMOTING
595 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
597 if (!callbacks.create_remoting_trampoline)
598 g_error ("remoting not installed");
599 return callbacks.create_remoting_trampoline (domain, method, target, error);
604 static MonoImtTrampolineBuilder imt_trampoline_builder;
605 static gboolean always_build_imt_trampolines;
607 #if (MONO_IMT_SIZE > 32)
608 #error "MONO_IMT_SIZE cannot be larger than 32"
612 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
614 memcpy (&callbacks, cbs, sizeof (*cbs));
617 MonoRuntimeCallbacks*
618 mono_get_runtime_callbacks (void)
624 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
626 imt_trampoline_builder = func;
630 mono_set_always_build_imt_trampolines (gboolean value)
632 always_build_imt_trampolines = value;
636 * mono_compile_method:
637 * \param method The method to compile.
638 * This JIT-compiles the method, and returns the pointer to the native code
642 mono_compile_method (MonoMethod *method)
645 gpointer result = mono_compile_method_checked (method, &error);
646 mono_error_cleanup (&error);
651 * mono_compile_method_checked:
652 * \param method The method to compile.
653 * \param error set on error.
654 * This JIT-compiles the method, and returns the pointer to the native code
655 * produced. On failure returns NULL and sets \p error.
658 mono_compile_method_checked (MonoMethod *method, MonoError *error)
662 MONO_REQ_GC_NEUTRAL_MODE
666 g_assert (callbacks.compile_method);
667 res = callbacks.compile_method (method, error);
672 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
676 MONO_REQ_GC_NEUTRAL_MODE;
679 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
684 mono_runtime_create_delegate_trampoline (MonoClass *klass)
686 MONO_REQ_GC_NEUTRAL_MODE
688 g_assert (callbacks.create_delegate_trampoline);
689 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
693 * mono_runtime_free_method:
694 * \param domain domain where the method is hosted
695 * \param method method to release
696 * This routine is invoked to free the resources associated with
697 * a method that has been JIT compiled. This is used to discard
698 * methods that were used only temporarily (for example, used in marshalling)
701 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
703 MONO_REQ_GC_NEUTRAL_MODE
705 if (callbacks.free_method)
706 callbacks.free_method (domain, method);
708 mono_method_clear_object (domain, method);
710 mono_free_method (method);
714 * The vtables in the root appdomain are assumed to be reachable by other
715 * roots, and we don't use typed allocation in the other domains.
718 /* The sync block is no longer a GC pointer */
719 #define GC_HEADER_BITMAP (0)
721 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
724 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
726 MONO_REQ_GC_NEUTRAL_MODE;
728 MonoClassField *field;
734 max_size = mono_class_data_size (klass) / sizeof (gpointer);
736 max_size = klass->instance_size / sizeof (gpointer);
737 if (max_size > size) {
738 g_assert (offset <= 0);
739 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
744 /*An Ephemeron cannot be marked by sgen*/
745 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
747 memset (bitmap, 0, size / 8);
752 for (p = klass; p != NULL; p = p->parent) {
753 gpointer iter = NULL;
754 while ((field = mono_class_get_fields (p, &iter))) {
758 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
760 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
763 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
766 /* FIXME: should not happen, flag as type load error */
767 if (field->type->byref)
770 if (static_fields && field->offset == -1)
774 pos = field->offset / sizeof (gpointer);
777 type = mono_type_get_underlying_type (field->type);
778 switch (type->type) {
782 case MONO_TYPE_FNPTR:
784 case MONO_TYPE_STRING:
785 case MONO_TYPE_SZARRAY:
786 case MONO_TYPE_CLASS:
787 case MONO_TYPE_OBJECT:
788 case MONO_TYPE_ARRAY:
789 g_assert ((field->offset % sizeof(gpointer)) == 0);
791 g_assert (pos < size || pos <= max_size);
792 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
793 *max_set = MAX (*max_set, pos);
795 case MONO_TYPE_GENERICINST:
796 if (!mono_type_generic_inst_is_valuetype (type)) {
797 g_assert ((field->offset % sizeof(gpointer)) == 0);
799 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
800 *max_set = MAX (*max_set, pos);
805 case MONO_TYPE_VALUETYPE: {
806 MonoClass *fclass = mono_class_from_mono_type (field->type);
807 if (fclass->has_references) {
808 /* remove the object header */
809 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
823 case MONO_TYPE_BOOLEAN:
827 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
838 * mono_class_compute_bitmap:
840 * Mono internal function to compute a bitmap of reference fields in a class.
843 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
845 MONO_REQ_GC_NEUTRAL_MODE;
847 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
852 * similar to the above, but sets the bits in the bitmap for any non-ref field
853 * and ignores static fields
856 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
858 MonoClassField *field;
863 max_size = class->instance_size / sizeof (gpointer);
864 if (max_size >= size) {
865 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
868 for (p = class; p != NULL; p = p->parent) {
869 gpointer iter = NULL;
870 while ((field = mono_class_get_fields (p, &iter))) {
873 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
875 /* FIXME: should not happen, flag as type load error */
876 if (field->type->byref)
879 pos = field->offset / sizeof (gpointer);
882 type = mono_type_get_underlying_type (field->type);
883 switch (type->type) {
884 #if SIZEOF_VOID_P == 8
888 case MONO_TYPE_FNPTR:
893 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
894 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
895 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
898 #if SIZEOF_VOID_P == 4
902 case MONO_TYPE_FNPTR:
907 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
908 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
909 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
915 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
916 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
917 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
920 case MONO_TYPE_BOOLEAN:
923 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
925 case MONO_TYPE_STRING:
926 case MONO_TYPE_SZARRAY:
927 case MONO_TYPE_CLASS:
928 case MONO_TYPE_OBJECT:
929 case MONO_TYPE_ARRAY:
931 case MONO_TYPE_GENERICINST:
932 if (!mono_type_generic_inst_is_valuetype (type)) {
937 case MONO_TYPE_VALUETYPE: {
938 MonoClass *fclass = mono_class_from_mono_type (field->type);
939 /* remove the object header */
940 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
944 g_assert_not_reached ();
953 * mono_class_insecure_overlapping:
954 * check if a class with explicit layout has references and non-references
955 * fields overlapping.
957 * Returns: TRUE if it is insecure to load the type.
960 mono_class_insecure_overlapping (MonoClass *klass)
964 gsize default_bitmap [4] = {0};
966 gsize default_nrbitmap [4] = {0};
967 int i, insecure = FALSE;
970 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
971 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
973 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
974 int idx = i % (sizeof (bitmap [0]) * 8);
975 if (bitmap [idx] & nrbitmap [idx]) {
980 if (bitmap != default_bitmap)
982 if (nrbitmap != default_nrbitmap)
985 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
993 ves_icall_string_alloc (int length)
996 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
997 mono_error_set_pending_exception (&error);
1002 /* LOCKING: Acquires the loader lock */
1004 mono_class_compute_gc_descriptor (MonoClass *klass)
1006 MONO_REQ_GC_NEUTRAL_MODE;
1010 gsize default_bitmap [4] = {0};
1011 static gboolean gcj_inited = FALSE;
1012 MonoGCDescriptor gc_descr;
1015 mono_loader_lock ();
1017 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1018 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1021 mono_loader_unlock ();
1025 mono_class_init (klass);
1027 if (klass->gc_descr_inited)
1030 bitmap = default_bitmap;
1031 if (klass == mono_defaults.string_class) {
1032 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1033 } else if (klass->rank) {
1034 mono_class_compute_gc_descriptor (klass->element_class);
1035 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1037 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1038 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1039 class->name_space, class->name);*/
1041 /* remove the object header */
1042 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1043 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));
1044 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1045 class->name_space, class->name);*/
1046 if (bitmap != default_bitmap)
1050 /*static int count = 0;
1053 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1054 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1056 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1057 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1059 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1060 if (bitmap != default_bitmap)
1064 /* Publish the data */
1065 mono_loader_lock ();
1066 klass->gc_descr = gc_descr;
1067 mono_memory_barrier ();
1068 klass->gc_descr_inited = TRUE;
1069 mono_loader_unlock ();
1073 * field_is_special_static:
1074 * @fklass: The MonoClass to look up.
1075 * @field: The MonoClassField describing the field.
1077 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1078 * SPECIAL_STATIC_NONE otherwise.
1081 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1083 MONO_REQ_GC_NEUTRAL_MODE;
1086 MonoCustomAttrInfo *ainfo;
1088 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1089 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1092 for (i = 0; i < ainfo->num_attrs; ++i) {
1093 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1094 if (klass->image == mono_defaults.corlib) {
1095 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1096 mono_custom_attrs_free (ainfo);
1097 return SPECIAL_STATIC_THREAD;
1099 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1100 mono_custom_attrs_free (ainfo);
1101 return SPECIAL_STATIC_CONTEXT;
1105 mono_custom_attrs_free (ainfo);
1106 return SPECIAL_STATIC_NONE;
1109 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1110 #define mix(a,b,c) { \
1111 a -= c; a ^= rot(c, 4); c += b; \
1112 b -= a; b ^= rot(a, 6); a += c; \
1113 c -= b; c ^= rot(b, 8); b += a; \
1114 a -= c; a ^= rot(c,16); c += b; \
1115 b -= a; b ^= rot(a,19); a += c; \
1116 c -= b; c ^= rot(b, 4); b += a; \
1118 #define final(a,b,c) { \
1119 c ^= b; c -= rot(b,14); \
1120 a ^= c; a -= rot(c,11); \
1121 b ^= a; b -= rot(a,25); \
1122 c ^= b; c -= rot(b,16); \
1123 a ^= c; a -= rot(c,4); \
1124 b ^= a; b -= rot(a,14); \
1125 c ^= b; c -= rot(b,24); \
1129 * mono_method_get_imt_slot:
1131 * The IMT slot is embedded into AOTed code, so this must return the same value
1132 * for the same method across all executions. This means:
1133 * - pointers shouldn't be used as hash values.
1134 * - mono_metadata_str_hash () should be used for hashing strings.
1137 mono_method_get_imt_slot (MonoMethod *method)
1139 MONO_REQ_GC_NEUTRAL_MODE;
1141 MonoMethodSignature *sig;
1143 guint32 *hashes_start, *hashes;
1147 /* This can be used to stress tests the collision code */
1151 * We do this to simplify generic sharing. It will hurt
1152 * performance in cases where a class implements two different
1153 * instantiations of the same generic interface.
1154 * The code in build_imt_slots () depends on this.
1156 if (method->is_inflated)
1157 method = ((MonoMethodInflated*)method)->declaring;
1159 sig = mono_method_signature (method);
1160 hashes_count = sig->param_count + 4;
1161 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1162 hashes = hashes_start;
1164 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1165 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1166 method->klass->name_space, method->klass->name, method->name);
1169 /* Initialize hashes */
1170 hashes [0] = mono_metadata_str_hash (method->klass->name);
1171 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1172 hashes [2] = mono_metadata_str_hash (method->name);
1173 hashes [3] = mono_metadata_type_hash (sig->ret);
1174 for (i = 0; i < sig->param_count; i++) {
1175 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1178 /* Setup internal state */
1179 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1181 /* Handle most of the hashes */
1182 while (hashes_count > 3) {
1191 /* Handle the last 3 hashes (all the case statements fall through) */
1192 switch (hashes_count) {
1193 case 3 : c += hashes [2];
1194 case 2 : b += hashes [1];
1195 case 1 : a += hashes [0];
1197 case 0: /* nothing left to add */
1201 g_free (hashes_start);
1202 /* Report the result */
1203 return c % MONO_IMT_SIZE;
1212 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1213 MONO_REQ_GC_NEUTRAL_MODE;
1215 guint32 imt_slot = mono_method_get_imt_slot (method);
1216 MonoImtBuilderEntry *entry;
1218 if (slot_num >= 0 && imt_slot != slot_num) {
1219 /* we build just a single imt slot and this is not it */
1223 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1224 entry->key = method;
1225 entry->value.vtable_slot = vtable_slot;
1226 entry->next = imt_builder [imt_slot];
1227 if (imt_builder [imt_slot] != NULL) {
1228 entry->children = imt_builder [imt_slot]->children + 1;
1229 if (entry->children == 1) {
1230 mono_stats.imt_slots_with_collisions++;
1231 *imt_collisions_bitmap |= (1 << imt_slot);
1234 entry->children = 0;
1235 mono_stats.imt_used_slots++;
1237 imt_builder [imt_slot] = entry;
1240 char *method_name = mono_method_full_name (method, TRUE);
1241 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1242 method, method_name, imt_slot, vtable_slot, entry->children);
1243 g_free (method_name);
1250 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1252 MonoMethod *method = e->key;
1253 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1257 method->klass->name_space,
1258 method->klass->name,
1261 printf (" * %s: NULL\n", message);
1267 compare_imt_builder_entries (const void *p1, const void *p2) {
1268 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1269 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1271 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1275 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1277 MONO_REQ_GC_NEUTRAL_MODE;
1279 int count = end - start;
1280 int chunk_start = out_array->len;
1283 for (i = start; i < end; ++i) {
1284 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1285 item->key = sorted_array [i]->key;
1286 item->value = sorted_array [i]->value;
1287 item->has_target_code = sorted_array [i]->has_target_code;
1288 item->is_equals = TRUE;
1290 item->check_target_idx = out_array->len + 1;
1292 item->check_target_idx = 0;
1293 g_ptr_array_add (out_array, item);
1296 int middle = start + count / 2;
1297 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1299 item->key = sorted_array [middle]->key;
1300 item->is_equals = FALSE;
1301 g_ptr_array_add (out_array, item);
1302 imt_emit_ir (sorted_array, start, middle, out_array);
1303 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1309 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1310 MONO_REQ_GC_NEUTRAL_MODE;
1312 int number_of_entries = entries->children + 1;
1313 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1314 GPtrArray *result = g_ptr_array_new ();
1315 MonoImtBuilderEntry *current_entry;
1318 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1319 sorted_array [i] = current_entry;
1321 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1323 /*for (i = 0; i < number_of_entries; i++) {
1324 print_imt_entry (" sorted array:", sorted_array [i], i);
1327 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1329 g_free (sorted_array);
1334 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1336 MONO_REQ_GC_NEUTRAL_MODE;
1338 if (imt_builder_entry != NULL) {
1339 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1340 /* No collision, return the vtable slot contents */
1341 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1343 /* Collision, build the trampoline */
1344 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1347 result = imt_trampoline_builder (vtable, domain,
1348 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1349 for (i = 0; i < imt_ir->len; ++i)
1350 g_free (g_ptr_array_index (imt_ir, i));
1351 g_ptr_array_free (imt_ir, TRUE);
1363 static MonoImtBuilderEntry*
1364 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1367 * LOCKING: requires the loader and domain locks.
1371 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1373 MONO_REQ_GC_NEUTRAL_MODE;
1377 guint32 imt_collisions_bitmap = 0;
1378 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1379 int method_count = 0;
1380 gboolean record_method_count_for_max_collisions = FALSE;
1381 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1384 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1386 for (i = 0; i < klass->interface_offsets_count; ++i) {
1387 MonoClass *iface = klass->interfaces_packed [i];
1388 int interface_offset = klass->interface_offsets_packed [i];
1389 int method_slot_in_interface, vt_slot;
1391 if (mono_class_has_variant_generic_params (iface))
1392 has_variant_iface = TRUE;
1394 mono_class_setup_methods (iface);
1395 vt_slot = interface_offset;
1396 int mcount = mono_class_get_method_count (iface);
1397 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1400 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1402 * The imt slot of the method is the same as for its declaring method,
1403 * see the comment in mono_method_get_imt_slot (), so we can
1404 * avoid inflating methods which will be discarded by
1405 * add_imt_builder_entry anyway.
1407 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1408 if (mono_method_get_imt_slot (method) != slot_num) {
1413 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1414 if (method->is_generic) {
1415 has_generic_virtual = TRUE;
1420 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1421 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1426 if (extra_interfaces) {
1427 int interface_offset = klass->vtable_size;
1429 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1430 MonoClass* iface = (MonoClass *)list_item->data;
1431 int method_slot_in_interface;
1432 int mcount = mono_class_get_method_count (iface);
1433 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1434 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1436 if (method->is_generic)
1437 has_generic_virtual = TRUE;
1438 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1440 interface_offset += mcount;
1443 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1444 /* overwrite the imt slot only if we're building all the entries or if
1445 * we're building this specific one
1447 if (slot_num < 0 || i == slot_num) {
1448 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1451 if (imt_builder [i]) {
1452 MonoImtBuilderEntry *entry;
1454 /* Link entries with imt_builder [i] */
1455 for (entry = entries; entry->next; entry = entry->next) {
1457 MonoMethod *method = (MonoMethod*)entry->key;
1458 char *method_name = mono_method_full_name (method, TRUE);
1459 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1460 g_free (method_name);
1463 entry->next = imt_builder [i];
1464 entries->children += imt_builder [i]->children + 1;
1466 imt_builder [i] = entries;
1469 if (has_generic_virtual || has_variant_iface) {
1471 * There might be collisions later when the the trampoline is expanded.
1473 imt_collisions_bitmap |= (1 << i);
1476 * The IMT trampoline might be called with an instance of one of the
1477 * generic virtual methods, so has to fallback to the IMT trampoline.
1479 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1481 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1484 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1488 if (imt_builder [i] != NULL) {
1489 int methods_in_slot = imt_builder [i]->children + 1;
1490 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1491 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1492 record_method_count_for_max_collisions = TRUE;
1494 method_count += methods_in_slot;
1498 mono_stats.imt_number_of_methods += method_count;
1499 if (record_method_count_for_max_collisions) {
1500 mono_stats.imt_method_count_when_max_collisions = method_count;
1503 for (i = 0; i < MONO_IMT_SIZE; i++) {
1504 MonoImtBuilderEntry* entry = imt_builder [i];
1505 while (entry != NULL) {
1506 MonoImtBuilderEntry* next = entry->next;
1511 g_free (imt_builder);
1512 /* we OR the bitmap since we may build just a single imt slot at a time */
1513 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1517 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1518 MONO_REQ_GC_NEUTRAL_MODE;
1520 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1524 * mono_vtable_build_imt_slot:
1525 * \param vtable virtual object table struct
1526 * \param imt_slot slot in the IMT table
1527 * Fill the given \p imt_slot in the IMT table of \p vtable with
1528 * a trampoline or a trampoline for the case of collisions.
1529 * This is part of the internal mono API.
1530 * LOCKING: Take the domain lock.
1533 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1535 MONO_REQ_GC_NEUTRAL_MODE;
1537 gpointer *imt = (gpointer*)vtable;
1538 imt -= MONO_IMT_SIZE;
1539 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1541 /* no support for extra interfaces: the proxy objects will need
1542 * to build the complete IMT
1543 * Update and heck needs to ahppen inside the proper domain lock, as all
1544 * the changes made to a MonoVTable.
1546 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1547 mono_domain_lock (vtable->domain);
1548 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1549 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1550 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1551 mono_domain_unlock (vtable->domain);
1552 mono_loader_unlock ();
1555 #define THUNK_THRESHOLD 10
1558 * mono_method_alloc_generic_virtual_trampoline:
1559 * \param domain a domain
1560 * \param size size in bytes
1561 * Allocs \p size bytes to be used for the code of a generic virtual
1562 * trampoline. It's either allocated from the domain's code manager or
1563 * reused from a previously invalidated piece.
1564 * LOCKING: The domain lock must be held.
1567 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1569 MONO_REQ_GC_NEUTRAL_MODE;
1571 static gboolean inited = FALSE;
1572 static int generic_virtual_trampolines_size = 0;
1575 mono_counters_register ("Generic virtual trampoline bytes",
1576 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1579 generic_virtual_trampolines_size += size;
1581 return mono_domain_code_reserve (domain, size);
1584 typedef struct _GenericVirtualCase {
1588 struct _GenericVirtualCase *next;
1589 } GenericVirtualCase;
1592 * get_generic_virtual_entries:
1594 * Return IMT entries for the generic virtual method instances and
1595 * variant interface methods for vtable slot
1598 static MonoImtBuilderEntry*
1599 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1601 MONO_REQ_GC_NEUTRAL_MODE;
1603 GenericVirtualCase *list;
1604 MonoImtBuilderEntry *entries;
1606 mono_domain_lock (domain);
1607 if (!domain->generic_virtual_cases)
1608 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1610 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1613 for (; list; list = list->next) {
1614 MonoImtBuilderEntry *entry;
1616 if (list->count < THUNK_THRESHOLD)
1619 entry = g_new0 (MonoImtBuilderEntry, 1);
1620 entry->key = list->method;
1621 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1622 entry->has_target_code = 1;
1624 entry->children = entries->children + 1;
1625 entry->next = entries;
1629 mono_domain_unlock (domain);
1631 /* FIXME: Leaking memory ? */
1636 * \param domain a domain
1637 * \param vtable_slot pointer to the vtable slot
1638 * \param method the inflated generic virtual method
1639 * \param code the method's code
1641 * Registers a call via unmanaged code to a generic virtual method
1642 * instantiation or variant interface method. If the number of calls reaches a threshold
1643 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1644 * virtual method trampoline.
1647 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1648 gpointer *vtable_slot,
1649 MonoMethod *method, gpointer code)
1651 MONO_REQ_GC_NEUTRAL_MODE;
1653 static gboolean inited = FALSE;
1654 static int num_added = 0;
1655 static int num_freed = 0;
1657 GenericVirtualCase *gvc, *list;
1658 MonoImtBuilderEntry *entries;
1662 mono_domain_lock (domain);
1663 if (!domain->generic_virtual_cases)
1664 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1667 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1668 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1672 /* Check whether the case was already added */
1673 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1676 if (gvc->method == method)
1681 /* If not found, make a new one */
1683 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1684 gvc->method = method;
1687 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1689 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1694 if (++gvc->count == THUNK_THRESHOLD) {
1695 gpointer *old_thunk = (void **)*vtable_slot;
1696 gpointer vtable_trampoline = NULL;
1697 gpointer imt_trampoline = NULL;
1699 if ((gpointer)vtable_slot < (gpointer)vtable) {
1700 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1701 int imt_slot = MONO_IMT_SIZE + displacement;
1703 /* Force the rebuild of the trampoline at the next call */
1704 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1705 *vtable_slot = imt_trampoline;
1707 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1709 entries = get_generic_virtual_entries (domain, vtable_slot);
1711 sorted = imt_sort_slot_entries (entries);
1713 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1717 MonoImtBuilderEntry *next = entries->next;
1722 for (i = 0; i < sorted->len; ++i)
1723 g_free (g_ptr_array_index (sorted, i));
1724 g_ptr_array_free (sorted, TRUE);
1726 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1731 mono_domain_unlock (domain);
1734 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1737 * mono_class_vtable:
1738 * \param domain the application domain
1739 * \param class the class to initialize
1740 * VTables are domain specific because we create domain specific code, and
1741 * they contain the domain specific static class data.
1742 * On failure, NULL is returned, and \c class->exception_type is set.
1745 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1748 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1749 mono_error_cleanup (&error);
1754 * mono_class_vtable_full:
1755 * \param domain the application domain
1756 * \param class the class to initialize
1757 * \param error set on failure.
1758 * VTables are domain specific because we create domain specific code, and
1759 * they contain the domain specific static class data.
1762 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1764 MONO_REQ_GC_UNSAFE_MODE;
1766 MonoClassRuntimeInfo *runtime_info;
1772 if (mono_class_has_failure (klass)) {
1773 mono_error_set_for_class_failure (error, klass);
1777 /* this check can be inlined in jitted code, too */
1778 runtime_info = klass->runtime_info;
1779 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1780 return runtime_info->domain_vtables [domain->domain_id];
1781 return mono_class_create_runtime_vtable (domain, klass, error);
1785 * mono_class_try_get_vtable:
1786 * \param domain the application domain
1787 * \param class the class to initialize
1788 * This function tries to get the associated vtable from \p class if
1789 * it was already created.
1792 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1794 MONO_REQ_GC_NEUTRAL_MODE;
1796 MonoClassRuntimeInfo *runtime_info;
1800 runtime_info = klass->runtime_info;
1801 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1802 return runtime_info->domain_vtables [domain->domain_id];
1807 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1809 MONO_REQ_GC_NEUTRAL_MODE;
1811 size_t alloc_offset;
1814 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1815 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1816 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1818 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1819 g_assert ((imt_table_bytes & 7) == 4);
1826 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1830 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1832 MONO_REQ_GC_UNSAFE_MODE;
1835 MonoClassRuntimeInfo *runtime_info, *old_info;
1836 MonoClassField *field;
1838 int i, vtable_slots;
1839 size_t imt_table_bytes;
1841 guint32 vtable_size, class_size;
1843 gpointer *interface_offsets;
1847 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1848 mono_domain_lock (domain);
1849 runtime_info = klass->runtime_info;
1850 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1851 mono_domain_unlock (domain);
1852 mono_loader_unlock ();
1853 return runtime_info->domain_vtables [domain->domain_id];
1855 if (!klass->inited || mono_class_has_failure (klass)) {
1856 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1857 mono_domain_unlock (domain);
1858 mono_loader_unlock ();
1859 mono_error_set_for_class_failure (error, klass);
1864 /* Array types require that their element type be valid*/
1865 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1866 MonoClass *element_class = klass->element_class;
1867 if (!element_class->inited)
1868 mono_class_init (element_class);
1870 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1871 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1872 mono_class_setup_vtable (element_class);
1874 if (mono_class_has_failure (element_class)) {
1875 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1876 if (!mono_class_has_failure (klass))
1877 mono_class_set_type_load_failure (klass, "");
1878 mono_domain_unlock (domain);
1879 mono_loader_unlock ();
1880 mono_error_set_for_class_failure (error, klass);
1886 * For some classes, mono_class_init () already computed klass->vtable_size, and
1887 * that is all that is needed because of the vtable trampolines.
1889 if (!klass->vtable_size)
1890 mono_class_setup_vtable (klass);
1892 if (mono_class_is_ginst (klass) && !klass->vtable)
1893 mono_class_check_vtable_constraints (klass, NULL);
1895 /* Initialize klass->has_finalize */
1896 mono_class_has_finalizer (klass);
1898 if (mono_class_has_failure (klass)) {
1899 mono_domain_unlock (domain);
1900 mono_loader_unlock ();
1901 mono_error_set_for_class_failure (error, klass);
1905 vtable_slots = klass->vtable_size;
1906 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1907 class_size = mono_class_data_size (klass);
1911 if (klass->interface_offsets_count) {
1912 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1913 mono_stats.imt_number_of_tables++;
1914 mono_stats.imt_tables_size += imt_table_bytes;
1916 imt_table_bytes = 0;
1919 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1921 mono_stats.used_class_count++;
1922 mono_stats.class_vtable_size += vtable_size;
1924 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1925 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1926 g_assert (!((gsize)vt & 7));
1929 vt->rank = klass->rank;
1930 vt->domain = domain;
1932 mono_class_compute_gc_descriptor (klass);
1934 * We can't use typed allocation in the non-root domains, since the
1935 * collector needs the GC descriptor stored in the vtable even after
1936 * the mempool containing the vtable is destroyed when the domain is
1937 * unloaded. An alternative might be to allocate vtables in the GC
1938 * heap, but this does not seem to work (it leads to crashes inside
1939 * libgc). If that approach is tried, two gc descriptors need to be
1940 * allocated for each class: one for the root domain, and one for all
1941 * other domains. The second descriptor should contain a bit for the
1942 * vtable field in MonoObject, since we can no longer assume the
1943 * vtable is reachable by other roots after the appdomain is unloaded.
1945 #ifdef HAVE_BOEHM_GC
1946 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1947 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1950 vt->gc_descr = klass->gc_descr;
1952 gc_bits = mono_gc_get_vtable_bits (klass);
1953 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1955 vt->gc_bits = gc_bits;
1958 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1959 if (klass->has_static_refs) {
1960 MonoGCDescriptor statics_gc_descr;
1962 gsize default_bitmap [4] = {0};
1965 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1966 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1967 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1968 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1969 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1970 if (bitmap != default_bitmap)
1973 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1975 vt->has_static_fields = TRUE;
1976 mono_stats.class_static_data_size += class_size;
1980 while ((field = mono_class_get_fields (klass, &iter))) {
1981 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1983 if (mono_field_is_deleted (field))
1985 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1986 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1987 if (special_static != SPECIAL_STATIC_NONE) {
1988 guint32 size, offset;
1990 gsize default_bitmap [4] = {0};
1995 if (mono_type_is_reference (field->type)) {
1996 default_bitmap [0] = 1;
1998 bitmap = default_bitmap;
1999 } else if (mono_type_is_struct (field->type)) {
2000 fclass = mono_class_from_mono_type (field->type);
2001 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2002 numbits = max_set + 1;
2004 default_bitmap [0] = 0;
2006 bitmap = default_bitmap;
2008 size = mono_type_size (field->type, &align);
2009 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2010 if (!domain->special_static_fields)
2011 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2012 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2013 if (bitmap != default_bitmap)
2016 * This marks the field as special static to speed up the
2017 * checks in mono_field_static_get/set_value ().
2023 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2024 MonoClass *fklass = mono_class_from_mono_type (field->type);
2025 const char *data = mono_field_get_data (field);
2027 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2028 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2029 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2032 if (fklass->valuetype) {
2033 memcpy (t, data, mono_class_value_size (fklass, NULL));
2035 /* it's a pointer type: add check */
2036 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2043 vt->max_interface_id = klass->max_interface_id;
2044 vt->interface_bitmap = klass->interface_bitmap;
2046 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2047 // class->name, klass->interface_offsets_count);
2049 /* Initialize vtable */
2050 if (callbacks.get_vtable_trampoline) {
2051 // This also covers the AOT case
2052 for (i = 0; i < klass->vtable_size; ++i) {
2053 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2056 mono_class_setup_vtable (klass);
2058 for (i = 0; i < klass->vtable_size; ++i) {
2061 cm = klass->vtable [i];
2063 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2064 if (!is_ok (error)) {
2065 mono_domain_unlock (domain);
2066 mono_loader_unlock ();
2073 if (imt_table_bytes) {
2074 /* Now that the vtable is full, we can actually fill up the IMT */
2075 for (i = 0; i < MONO_IMT_SIZE; ++i)
2076 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2080 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2081 * re-acquire them and check if another thread has created the vtable in the meantime.
2083 /* Special case System.MonoType to avoid infinite recursion */
2084 if (klass != mono_defaults.runtimetype_class) {
2085 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2086 if (!is_ok (error)) {
2087 mono_domain_unlock (domain);
2088 mono_loader_unlock ();
2092 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2093 /* This is unregistered in
2094 unregister_vtable_reflection_type() in
2096 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2099 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2101 /* class_vtable_array keeps an array of created vtables
2103 g_ptr_array_add (domain->class_vtable_array, vt);
2104 /* klass->runtime_info is protected by the loader lock, both when
2105 * it it enlarged and when it is stored info.
2109 * Store the vtable in klass->runtime_info.
2110 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2112 mono_memory_barrier ();
2114 old_info = klass->runtime_info;
2115 if (old_info && old_info->max_domain >= domain->domain_id) {
2116 /* someone already created a large enough runtime info */
2117 old_info->domain_vtables [domain->domain_id] = vt;
2119 int new_size = domain->domain_id;
2121 new_size = MAX (new_size, old_info->max_domain);
2123 /* make the new size a power of two */
2125 while (new_size > i)
2128 /* this is a bounded memory retention issue: may want to
2129 * handle it differently when we'll have a rcu-like system.
2131 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2132 runtime_info->max_domain = new_size - 1;
2133 /* copy the stuff from the older info */
2135 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2137 runtime_info->domain_vtables [domain->domain_id] = vt;
2139 mono_memory_barrier ();
2140 klass->runtime_info = runtime_info;
2143 if (klass == mono_defaults.runtimetype_class) {
2144 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2145 if (!is_ok (error)) {
2146 mono_domain_unlock (domain);
2147 mono_loader_unlock ();
2151 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2152 /* This is unregistered in
2153 unregister_vtable_reflection_type() in
2155 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2158 mono_domain_unlock (domain);
2159 mono_loader_unlock ();
2161 /* make sure the parent is initialized */
2162 /*FIXME shouldn't this fail the current type?*/
2164 mono_class_vtable_full (domain, klass->parent, error);
2169 #ifndef DISABLE_REMOTING
2171 * mono_class_proxy_vtable:
2172 * \param domain the application domain
2173 * \param remove_class the remote class
2174 * \param error set on error
2175 * Creates a vtable for transparent proxies. It is basically
2176 * a copy of the real vtable of the class wrapped in \p remote_class,
2177 * but all function pointers invoke the remoting functions, and
2178 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2180 * On failure returns NULL and sets \p error
2183 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2185 MONO_REQ_GC_UNSAFE_MODE;
2187 MonoVTable *vt, *pvt;
2188 int i, j, vtsize, extra_interface_vtsize = 0;
2189 guint32 max_interface_id;
2191 GSList *extra_interfaces = NULL;
2192 MonoClass *klass = remote_class->proxy_class;
2193 gpointer *interface_offsets;
2194 uint8_t *bitmap = NULL;
2196 size_t imt_table_bytes;
2198 #ifdef COMPRESSED_INTERFACE_BITMAP
2204 vt = mono_class_vtable (domain, klass);
2205 g_assert (vt); /*FIXME property handle failure*/
2206 max_interface_id = vt->max_interface_id;
2208 /* Calculate vtable space for extra interfaces */
2209 for (j = 0; j < remote_class->interface_count; j++) {
2210 MonoClass* iclass = remote_class->interfaces[j];
2214 /*FIXME test for interfaces with variant generic arguments*/
2215 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2216 continue; /* interface implemented by the class */
2217 if (g_slist_find (extra_interfaces, iclass))
2220 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2222 method_count = mono_class_num_methods (iclass);
2224 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2228 for (i = 0; i < ifaces->len; ++i) {
2229 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2230 /*FIXME test for interfaces with variant generic arguments*/
2231 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2232 continue; /* interface implemented by the class */
2233 if (g_slist_find (extra_interfaces, ic))
2235 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2236 method_count += mono_class_num_methods (ic);
2238 g_ptr_array_free (ifaces, TRUE);
2242 extra_interface_vtsize += method_count * sizeof (gpointer);
2243 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2246 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2247 mono_stats.imt_number_of_tables++;
2248 mono_stats.imt_tables_size += imt_table_bytes;
2250 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2252 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2254 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2255 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2256 g_assert (!((gsize)pvt & 7));
2258 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2260 pvt->klass = mono_defaults.transparent_proxy_class;
2261 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2262 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2264 /* initialize vtable */
2265 mono_class_setup_vtable (klass);
2266 for (i = 0; i < klass->vtable_size; ++i) {
2269 if ((cm = klass->vtable [i])) {
2270 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2274 pvt->vtable [i] = NULL;
2277 if (mono_class_is_abstract (klass)) {
2278 /* create trampolines for abstract methods */
2279 for (k = klass; k; k = k->parent) {
2281 gpointer iter = NULL;
2282 while ((m = mono_class_get_methods (k, &iter)))
2283 if (!pvt->vtable [m->slot]) {
2284 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2291 pvt->max_interface_id = max_interface_id;
2292 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2293 #ifdef COMPRESSED_INTERFACE_BITMAP
2294 bitmap = (uint8_t *)g_malloc0 (bsize);
2296 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2299 for (i = 0; i < klass->interface_offsets_count; ++i) {
2300 int interface_id = klass->interfaces_packed [i]->interface_id;
2301 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2304 if (extra_interfaces) {
2305 int slot = klass->vtable_size;
2311 /* Create trampolines for the methods of the interfaces */
2312 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2313 interf = (MonoClass *)list_item->data;
2315 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2319 while ((cm = mono_class_get_methods (interf, &iter))) {
2320 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2325 slot += mono_class_num_methods (interf);
2329 /* Now that the vtable is full, we can actually fill up the IMT */
2330 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2331 if (extra_interfaces) {
2332 g_slist_free (extra_interfaces);
2335 #ifdef COMPRESSED_INTERFACE_BITMAP
2336 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2337 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2338 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2341 pvt->interface_bitmap = bitmap;
2345 if (extra_interfaces)
2346 g_slist_free (extra_interfaces);
2347 #ifdef COMPRESSED_INTERFACE_BITMAP
2353 #endif /* DISABLE_REMOTING */
2356 * mono_class_field_is_special_static:
2357 * \returns whether \p field is a thread/context static field.
2360 mono_class_field_is_special_static (MonoClassField *field)
2362 MONO_REQ_GC_NEUTRAL_MODE
2364 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2366 if (mono_field_is_deleted (field))
2368 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2369 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2376 * mono_class_field_get_special_static_type:
2377 * \param field The \c MonoClassField describing the field.
2378 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2379 * \c SPECIAL_STATIC_NONE otherwise.
2382 mono_class_field_get_special_static_type (MonoClassField *field)
2384 MONO_REQ_GC_NEUTRAL_MODE
2386 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2387 return SPECIAL_STATIC_NONE;
2388 if (mono_field_is_deleted (field))
2389 return SPECIAL_STATIC_NONE;
2390 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2391 return field_is_special_static (field->parent, field);
2392 return SPECIAL_STATIC_NONE;
2396 * mono_class_has_special_static_fields:
2397 * \returns whether \p klass has any thread/context static fields.
2400 mono_class_has_special_static_fields (MonoClass *klass)
2402 MONO_REQ_GC_NEUTRAL_MODE
2404 MonoClassField *field;
2408 while ((field = mono_class_get_fields (klass, &iter))) {
2409 g_assert (field->parent == klass);
2410 if (mono_class_field_is_special_static (field))
2417 #ifndef DISABLE_REMOTING
2419 * create_remote_class_key:
2420 * Creates an array of pointers that can be used as a hash key for a remote class.
2421 * The first element of the array is the number of pointers.
2424 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2426 MONO_REQ_GC_NEUTRAL_MODE;
2431 if (remote_class == NULL) {
2432 if (mono_class_is_interface (extra_class)) {
2433 key = (void **)g_malloc (sizeof(gpointer) * 3);
2434 key [0] = GINT_TO_POINTER (2);
2435 key [1] = mono_defaults.marshalbyrefobject_class;
2436 key [2] = extra_class;
2438 key = (void **)g_malloc (sizeof(gpointer) * 2);
2439 key [0] = GINT_TO_POINTER (1);
2440 key [1] = extra_class;
2443 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2444 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2445 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2446 key [1] = remote_class->proxy_class;
2448 // Keep the list of interfaces sorted
2449 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2450 if (extra_class && remote_class->interfaces [i] > extra_class) {
2451 key [j++] = extra_class;
2454 key [j] = remote_class->interfaces [i];
2457 key [j] = extra_class;
2459 // Replace the old class. The interface list is the same
2460 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2461 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2462 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2463 for (i = 0; i < remote_class->interface_count; i++)
2464 key [2 + i] = remote_class->interfaces [i];
2472 * copy_remote_class_key:
2474 * Make a copy of KEY in the domain and return the copy.
2477 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2479 MONO_REQ_GC_NEUTRAL_MODE
2481 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2482 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2484 memcpy (mp_key, key, key_size);
2490 * mono_remote_class:
2491 * \param domain the application domain
2492 * \param class_name name of the remote class
2493 * \param error set on error
2494 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2495 * On failure returns NULL and sets \p error
2498 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2500 MONO_REQ_GC_UNSAFE_MODE;
2502 MonoRemoteClass *rc;
2503 gpointer* key, *mp_key;
2508 key = create_remote_class_key (NULL, proxy_class);
2510 mono_domain_lock (domain);
2511 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2515 mono_domain_unlock (domain);
2519 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2520 if (!is_ok (error)) {
2522 mono_domain_unlock (domain);
2526 mp_key = copy_remote_class_key (domain, key);
2530 if (mono_class_is_interface (proxy_class)) {
2531 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2532 rc->interface_count = 1;
2533 rc->interfaces [0] = proxy_class;
2534 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2536 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2537 rc->interface_count = 0;
2538 rc->proxy_class = proxy_class;
2541 rc->default_vtable = NULL;
2542 rc->xdomain_vtable = NULL;
2543 rc->proxy_class_name = name;
2544 #ifndef DISABLE_PERFCOUNTERS
2545 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2548 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2550 mono_domain_unlock (domain);
2555 * clone_remote_class:
2556 * Creates a copy of the remote_class, adding the provided class or interface
2558 static MonoRemoteClass*
2559 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2561 MONO_REQ_GC_NEUTRAL_MODE;
2563 MonoRemoteClass *rc;
2564 gpointer* key, *mp_key;
2566 key = create_remote_class_key (remote_class, extra_class);
2567 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2573 mp_key = copy_remote_class_key (domain, key);
2577 if (mono_class_is_interface (extra_class)) {
2579 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2580 rc->proxy_class = remote_class->proxy_class;
2581 rc->interface_count = remote_class->interface_count + 1;
2583 // Keep the list of interfaces sorted, since the hash key of
2584 // the remote class depends on this
2585 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2586 if (remote_class->interfaces [i] > extra_class && i == j)
2587 rc->interfaces [j++] = extra_class;
2588 rc->interfaces [j] = remote_class->interfaces [i];
2591 rc->interfaces [j] = extra_class;
2593 // Replace the old class. The interface array is the same
2594 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2595 rc->proxy_class = extra_class;
2596 rc->interface_count = remote_class->interface_count;
2597 if (rc->interface_count > 0)
2598 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2601 rc->default_vtable = NULL;
2602 rc->xdomain_vtable = NULL;
2603 rc->proxy_class_name = remote_class->proxy_class_name;
2605 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2611 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2613 MONO_REQ_GC_UNSAFE_MODE;
2617 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2618 mono_domain_lock (domain);
2619 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2620 if (target_domain_id != -1) {
2621 if (remote_class->xdomain_vtable == NULL)
2622 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2623 mono_domain_unlock (domain);
2624 mono_loader_unlock ();
2625 return_val_if_nok (error, NULL);
2626 return remote_class->xdomain_vtable;
2628 if (remote_class->default_vtable == NULL) {
2629 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2630 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2632 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2633 MonoClass *klass = mono_class_from_mono_type (type);
2635 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)))
2636 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2639 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2640 /* N.B. both branches of the if modify error */
2641 if (!is_ok (error)) {
2642 mono_domain_unlock (domain);
2643 mono_loader_unlock ();
2648 mono_domain_unlock (domain);
2649 mono_loader_unlock ();
2650 return remote_class->default_vtable;
2654 * mono_upgrade_remote_class:
2655 * \param domain the application domain
2656 * \param tproxy the proxy whose remote class has to be upgraded.
2657 * \param klass class to which the remote class can be casted.
2658 * \param error set on error
2659 * Updates the vtable of the remote class by adding the necessary method slots
2660 * and interface offsets so it can be safely casted to klass. klass can be a
2661 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2664 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2666 MONO_REQ_GC_UNSAFE_MODE;
2670 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2671 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2673 gboolean redo_vtable;
2674 if (mono_class_is_interface (klass)) {
2677 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2678 if (remote_class->interfaces [i] == klass)
2679 redo_vtable = FALSE;
2682 redo_vtable = (remote_class->proxy_class != klass);
2685 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2686 mono_domain_lock (domain);
2688 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2689 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2690 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2691 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2692 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2698 mono_domain_unlock (domain);
2699 mono_loader_unlock ();
2700 return is_ok (error);
2702 #endif /* DISABLE_REMOTING */
2706 * mono_object_get_virtual_method:
2707 * \param obj object to operate on.
2708 * \param method method
2709 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2710 * the instance of a callvirt of \p method.
2713 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2715 MONO_REQ_GC_UNSAFE_MODE;
2716 HANDLE_FUNCTION_ENTER ();
2718 MONO_HANDLE_DCL (MonoObject, obj);
2719 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2720 mono_error_assert_ok (&error);
2721 HANDLE_FUNCTION_RETURN_VAL (result);
2725 * mono_object_handle_get_virtual_method:
2726 * \param obj object to operate on.
2727 * \param method method
2728 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2729 * the instance of a callvirt of \p method.
2732 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2736 gboolean is_proxy = FALSE;
2737 MonoClass *klass = mono_handle_class (obj);
2738 if (mono_class_is_transparent_proxy (klass)) {
2739 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2740 klass = remote_class->proxy_class;
2743 return class_get_virtual_method (klass, method, is_proxy, error);
2747 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2752 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2755 mono_class_setup_vtable (klass);
2756 MonoMethod **vtable = klass->vtable;
2758 if (method->slot == -1) {
2759 /* method->slot might not be set for instances of generic methods */
2760 if (method->is_inflated) {
2761 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2762 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2765 g_assert_not_reached ();
2769 MonoMethod *res = NULL;
2770 /* check method->slot is a valid index: perform isinstance? */
2771 if (method->slot != -1) {
2772 if (mono_class_is_interface (method->klass)) {
2774 gboolean variance_used = FALSE;
2775 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2776 g_assert (iface_offset > 0);
2777 res = vtable [iface_offset + method->slot];
2780 res = vtable [method->slot];
2784 #ifndef DISABLE_REMOTING
2786 /* It may be an interface, abstract class method or generic method */
2787 if (!res || mono_method_signature (res)->generic_param_count)
2790 /* generic methods demand invoke_with_check */
2791 if (mono_method_signature (res)->generic_param_count)
2792 res = mono_marshal_get_remoting_invoke_with_check (res);
2795 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2796 res = mono_cominterop_get_invoke (res);
2799 res = mono_marshal_get_remoting_invoke (res);
2804 if (method->is_inflated) {
2805 /* Have to inflate the result */
2806 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2814 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2816 MONO_REQ_GC_UNSAFE_MODE;
2818 MonoObject *result = NULL;
2820 g_assert (callbacks.runtime_invoke);
2824 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2825 mono_profiler_method_start_invoke (method);
2827 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2829 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2830 mono_profiler_method_end_invoke (method);
2832 if (!mono_error_ok (error))
2839 * mono_runtime_invoke:
2840 * \param method method to invoke
2841 * \param obj object instance
2842 * \param params arguments to the method
2843 * \param exc exception information.
2844 * Invokes the method represented by \p method on the object \p obj.
2845 * \p obj is the \c this pointer, it should be NULL for static
2846 * methods, a \c MonoObject* for object instances and a pointer to
2847 * the value type for value types.
2849 * The params array contains the arguments to the method with the
2850 * same convention: \c MonoObject* pointers for object instances and
2851 * pointers to the value type otherwise.
2853 * From unmanaged code you'll usually use the
2854 * mono_runtime_invoke() variant.
2856 * Note that this function doesn't handle virtual methods for
2857 * you, it will exec the exact method you pass: we still need to
2858 * expose a function to lookup the derived class implementation
2859 * of a virtual method (there are examples of this in the code,
2862 * You can pass NULL as the \p exc argument if you don't want to
2863 * catch exceptions, otherwise, \c *exc will be set to the exception
2864 * thrown, if any. if an exception is thrown, you can't use the
2865 * \c MonoObject* result from the function.
2867 * If the method returns a value type, it is boxed in an object
2871 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2876 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2877 if (*exc == NULL && !mono_error_ok(&error)) {
2878 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2880 mono_error_cleanup (&error);
2882 res = mono_runtime_invoke_checked (method, obj, params, &error);
2883 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2889 * mono_runtime_try_invoke:
2890 * \param method method to invoke
2891 * \param obj object instance
2892 * \param params arguments to the method
2893 * \param exc exception information.
2894 * \param error set on error
2895 * Invokes the method represented by \p method on the object \p obj.
2897 * \p obj is the \c this pointer, it should be NULL for static
2898 * methods, a \c MonoObject* for object instances and a pointer to
2899 * the value type for value types.
2901 * The params array contains the arguments to the method with the
2902 * same convention: \c MonoObject* pointers for object instances and
2903 * pointers to the value type otherwise.
2905 * From unmanaged code you'll usually use the
2906 * mono_runtime_invoke() variant.
2908 * Note that this function doesn't handle virtual methods for
2909 * you, it will exec the exact method you pass: we still need to
2910 * expose a function to lookup the derived class implementation
2911 * of a virtual method (there are examples of this in the code,
2914 * For this function, you must not pass NULL as the \p exc argument if
2915 * you don't want to catch exceptions, use
2916 * mono_runtime_invoke_checked(). If an exception is thrown, you
2917 * can't use the \c MonoObject* result from the function.
2919 * If this method cannot be invoked, \p error will be set and \p exc and
2920 * the return value must not be used.
2922 * If the method returns a value type, it is boxed in an object
2926 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2928 MONO_REQ_GC_UNSAFE_MODE;
2930 g_assert (exc != NULL);
2932 if (mono_runtime_get_no_exec ())
2933 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2935 return do_runtime_invoke (method, obj, params, exc, error);
2939 * mono_runtime_invoke_checked:
2940 * \param method method to invoke
2941 * \param obj object instance
2942 * \param params arguments to the method
2943 * \param error set on error
2944 * Invokes the method represented by \p method on the object \p obj.
2946 * \p obj is the \c this pointer, it should be NULL for static
2947 * methods, a \c MonoObject* for object instances and a pointer to
2948 * the value type for value types.
2950 * The \p params array contains the arguments to the method with the
2951 * same convention: \c MonoObject* pointers for object instances and
2952 * pointers to the value type otherwise.
2954 * From unmanaged code you'll usually use the
2955 * mono_runtime_invoke() variant.
2957 * Note that this function doesn't handle virtual methods for
2958 * you, it will exec the exact method you pass: we still need to
2959 * expose a function to lookup the derived class implementation
2960 * of a virtual method (there are examples of this in the code,
2963 * If an exception is thrown, you can't use the \c MonoObject* result
2964 * from the function.
2966 * If this method cannot be invoked, \p error will be set. If the
2967 * method throws an exception (and we're in coop mode) the exception
2968 * will be set in \p error.
2970 * If the method returns a value type, it is boxed in an object
2974 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2976 MONO_REQ_GC_UNSAFE_MODE;
2978 if (mono_runtime_get_no_exec ())
2979 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2981 return do_runtime_invoke (method, obj, params, NULL, error);
2985 * mono_method_get_unmanaged_thunk:
2986 * \param method method to generate a thunk for.
2988 * Returns an unmanaged->managed thunk that can be used to call
2989 * a managed method directly from C.
2991 * The thunk's C signature closely matches the managed signature:
2993 * C#: public bool Equals (object obj);
2994 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2995 * MonoObject*, MonoException**);
2997 * The 1st ("this") parameter must not be used with static methods:
2999 * C#: public static bool ReferenceEquals (object a, object b);
3000 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3003 * The last argument must be a non-null pointer of a MonoException* pointer.
3004 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3005 * exception has been thrown in managed code. Otherwise it will point
3006 * to the MonoException* caught by the thunk. In this case, the result of
3007 * the thunk is undefined:
3009 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3010 * MonoException *ex = NULL;
3011 * Equals func = mono_method_get_unmanaged_thunk (method);
3012 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3014 * // handle exception
3017 * The calling convention of the thunk matches the platform's default
3018 * convention. This means that under Windows, C declarations must
3019 * contain the __stdcall attribute:
3021 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3022 * MonoObject*, MonoException**);
3026 * Value type arguments and return values are treated as they were objects:
3028 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3029 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3031 * Arguments must be properly boxed upon trunk's invocation, while return
3032 * values must be unboxed.
3035 mono_method_get_unmanaged_thunk (MonoMethod *method)
3037 MONO_REQ_GC_NEUTRAL_MODE;
3038 MONO_REQ_API_ENTRYPOINT;
3043 g_assert (!mono_threads_is_coop_enabled ());
3045 MONO_ENTER_GC_UNSAFE;
3046 method = mono_marshal_get_thunk_invoke_wrapper (method);
3047 res = mono_compile_method_checked (method, &error);
3048 mono_error_cleanup (&error);
3049 MONO_EXIT_GC_UNSAFE;
3055 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3057 MONO_REQ_GC_UNSAFE_MODE;
3061 /* object fields cannot be byref, so we don't need a
3063 gpointer *p = (gpointer*)dest;
3070 case MONO_TYPE_BOOLEAN:
3072 case MONO_TYPE_U1: {
3073 guint8 *p = (guint8*)dest;
3074 *p = value ? *(guint8*)value : 0;
3079 case MONO_TYPE_CHAR: {
3080 guint16 *p = (guint16*)dest;
3081 *p = value ? *(guint16*)value : 0;
3084 #if SIZEOF_VOID_P == 4
3089 case MONO_TYPE_U4: {
3090 gint32 *p = (gint32*)dest;
3091 *p = value ? *(gint32*)value : 0;
3094 #if SIZEOF_VOID_P == 8
3099 case MONO_TYPE_U8: {
3100 gint64 *p = (gint64*)dest;
3101 *p = value ? *(gint64*)value : 0;
3104 case MONO_TYPE_R4: {
3105 float *p = (float*)dest;
3106 *p = value ? *(float*)value : 0;
3109 case MONO_TYPE_R8: {
3110 double *p = (double*)dest;
3111 *p = value ? *(double*)value : 0;
3114 case MONO_TYPE_STRING:
3115 case MONO_TYPE_SZARRAY:
3116 case MONO_TYPE_CLASS:
3117 case MONO_TYPE_OBJECT:
3118 case MONO_TYPE_ARRAY:
3119 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3121 case MONO_TYPE_FNPTR:
3122 case MONO_TYPE_PTR: {
3123 gpointer *p = (gpointer*)dest;
3124 *p = deref_pointer? *(gpointer*)value: value;
3127 case MONO_TYPE_VALUETYPE:
3128 /* note that 't' and 'type->type' can be different */
3129 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3130 t = mono_class_enum_basetype (type->data.klass)->type;
3133 MonoClass *klass = mono_class_from_mono_type (type);
3134 int size = mono_class_value_size (klass, NULL);
3136 mono_gc_bzero_atomic (dest, size);
3138 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3141 case MONO_TYPE_GENERICINST:
3142 t = type->data.generic_class->container_class->byval_arg.type;
3145 g_error ("got type %x", type->type);
3150 * mono_field_set_value:
3151 * \param obj Instance object
3152 * \param field \c MonoClassField describing the field to set
3153 * \param value The value to be set
3155 * Sets the value of the field described by \p field in the object instance \p obj
3156 * to the value passed in \p value. This method should only be used for instance
3157 * fields. For static fields, use mono_field_static_set_value().
3159 * The value must be in the native format of the field type.
3162 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3164 MONO_REQ_GC_UNSAFE_MODE;
3168 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3170 dest = (char*)obj + field->offset;
3171 mono_copy_value (field->type, dest, value, FALSE);
3175 * mono_field_static_set_value:
3176 * \param field \c MonoClassField describing the field to set
3177 * \param value The value to be set
3178 * Sets the value of the static field described by \p field
3179 * to the value passed in \p value.
3180 * The value must be in the native format of the field type.
3183 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3185 MONO_REQ_GC_UNSAFE_MODE;
3189 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3190 /* you cant set a constant! */
3191 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3193 if (field->offset == -1) {
3194 /* Special static */
3197 mono_domain_lock (vt->domain);
3198 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3199 mono_domain_unlock (vt->domain);
3200 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3202 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3204 mono_copy_value (field->type, dest, value, FALSE);
3208 * mono_vtable_get_static_field_data:
3210 * Internal use function: return a pointer to the memory holding the static fields
3211 * for a class or NULL if there are no static fields.
3212 * This is exported only for use by the debugger.
3215 mono_vtable_get_static_field_data (MonoVTable *vt)
3217 MONO_REQ_GC_NEUTRAL_MODE
3219 if (!vt->has_static_fields)
3221 return vt->vtable [vt->klass->vtable_size];
3225 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3227 MONO_REQ_GC_UNSAFE_MODE;
3231 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3232 if (field->offset == -1) {
3233 /* Special static */
3236 mono_domain_lock (vt->domain);
3237 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3238 mono_domain_unlock (vt->domain);
3239 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3241 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3244 src = (guint8*)obj + field->offset;
3251 * mono_field_get_value:
3252 * \param obj Object instance
3253 * \param field \c MonoClassField describing the field to fetch information from
3254 * \param value pointer to the location where the value will be stored
3255 * Use this routine to get the value of the field \p field in the object
3258 * The pointer provided by value must be of the field type, for reference
3259 * types this is a \c MonoObject*, for value types its the actual pointer to
3264 * mono_field_get_value (obj, int_field, &i);
3267 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3269 MONO_REQ_GC_UNSAFE_MODE;
3275 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3277 src = (char*)obj + field->offset;
3278 mono_copy_value (field->type, value, src, TRUE);
3282 * mono_field_get_value_object:
3283 * \param domain domain where the object will be created (if boxing)
3284 * \param field \c MonoClassField describing the field to fetch information from
3285 * \param obj The object instance for the field.
3286 * \returns a new \c MonoObject with the value from the given field. If the
3287 * field represents a value type, the value is boxed.
3290 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3293 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3294 mono_error_assert_ok (&error);
3299 * mono_field_get_value_object_checked:
3300 * \param domain domain where the object will be created (if boxing)
3301 * \param field \c MonoClassField describing the field to fetch information from
3302 * \param obj The object instance for the field.
3303 * \param error Set on error.
3304 * \returns a new \c MonoObject with the value from the given field. If the
3305 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3308 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3310 MONO_REQ_GC_UNSAFE_MODE;
3316 MonoVTable *vtable = NULL;
3318 gboolean is_static = FALSE;
3319 gboolean is_ref = FALSE;
3320 gboolean is_literal = FALSE;
3321 gboolean is_ptr = FALSE;
3322 MonoType *type = mono_field_get_type_checked (field, error);
3324 return_val_if_nok (error, NULL);
3326 switch (type->type) {
3327 case MONO_TYPE_STRING:
3328 case MONO_TYPE_OBJECT:
3329 case MONO_TYPE_CLASS:
3330 case MONO_TYPE_ARRAY:
3331 case MONO_TYPE_SZARRAY:
3336 case MONO_TYPE_BOOLEAN:
3339 case MONO_TYPE_CHAR:
3348 case MONO_TYPE_VALUETYPE:
3349 is_ref = type->byref;
3351 case MONO_TYPE_GENERICINST:
3352 is_ref = !mono_type_generic_inst_is_valuetype (type);
3358 g_error ("type 0x%x not handled in "
3359 "mono_field_get_value_object", type->type);
3363 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3366 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3370 vtable = mono_class_vtable_full (domain, field->parent, error);
3371 return_val_if_nok (error, NULL);
3373 if (!vtable->initialized) {
3374 mono_runtime_class_init_full (vtable, error);
3375 return_val_if_nok (error, NULL);
3384 get_default_field_value (domain, field, &o, error);
3385 return_val_if_nok (error, NULL);
3386 } else if (is_static) {
3387 mono_field_static_get_value_checked (vtable, field, &o, error);
3388 return_val_if_nok (error, NULL);
3390 mono_field_get_value (obj, field, &o);
3396 static MonoMethod *m;
3402 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3403 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3409 get_default_field_value (domain, field, v, error);
3410 return_val_if_nok (error, NULL);
3411 } else if (is_static) {
3412 mono_field_static_get_value_checked (vtable, field, v, error);
3413 return_val_if_nok (error, NULL);
3415 mono_field_get_value (obj, field, v);
3418 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3419 args [0] = ptr ? *ptr : NULL;
3420 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3421 return_val_if_nok (error, NULL);
3423 o = mono_runtime_invoke_checked (m, NULL, args, error);
3424 return_val_if_nok (error, NULL);
3429 /* boxed value type */
3430 klass = mono_class_from_mono_type (type);
3432 if (mono_class_is_nullable (klass))
3433 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3435 o = mono_object_new_checked (domain, klass, error);
3436 return_val_if_nok (error, NULL);
3437 v = ((gchar *) o) + sizeof (MonoObject);
3440 get_default_field_value (domain, field, v, error);
3441 return_val_if_nok (error, NULL);
3442 } else if (is_static) {
3443 mono_field_static_get_value_checked (vtable, field, v, error);
3444 return_val_if_nok (error, NULL);
3446 mono_field_get_value (obj, field, v);
3453 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3455 MONO_REQ_GC_UNSAFE_MODE;
3459 const char *p = blob;
3460 mono_metadata_decode_blob_size (p, &p);
3463 case MONO_TYPE_BOOLEAN:
3466 *(guint8 *) value = *p;
3468 case MONO_TYPE_CHAR:
3471 *(guint16*) value = read16 (p);
3475 *(guint32*) value = read32 (p);
3479 *(guint64*) value = read64 (p);
3482 readr4 (p, (float*) value);
3485 readr8 (p, (double*) value);
3487 case MONO_TYPE_STRING:
3488 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3490 case MONO_TYPE_CLASS:
3491 *(gpointer*) value = NULL;
3495 g_warning ("type 0x%02x should not be in constant table", type);
3501 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3503 MONO_REQ_GC_NEUTRAL_MODE;
3505 MonoTypeEnum def_type;
3510 data = mono_class_get_field_default_value (field, &def_type);
3511 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3515 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3517 MONO_REQ_GC_UNSAFE_MODE;
3523 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3525 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3526 get_default_field_value (vt->domain, field, value, error);
3530 if (field->offset == -1) {
3531 /* Special static */
3532 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3533 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3535 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3537 mono_copy_value (field->type, value, src, TRUE);
3541 * mono_field_static_get_value:
3542 * \param vt vtable to the object
3543 * \param field \c MonoClassField describing the field to fetch information from
3544 * \param value where the value is returned
3545 * Use this routine to get the value of the static field \p field value.
3547 * The pointer provided by value must be of the field type, for reference
3548 * types this is a \c MonoObject*, for value types its the actual pointer to
3553 * mono_field_static_get_value (vt, int_field, &i);
3556 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3558 MONO_REQ_GC_NEUTRAL_MODE;
3561 mono_field_static_get_value_checked (vt, field, value, &error);
3562 mono_error_cleanup (&error);
3566 * mono_field_static_get_value_checked:
3567 * \param vt vtable to the object
3568 * \param field \c MonoClassField describing the field to fetch information from
3569 * \param value where the value is returned
3570 * \param error set on error
3571 * Use this routine to get the value of the static field \p field value.
3573 * The pointer provided by value must be of the field type, for reference
3574 * types this is a \c MonoObject*, for value types its the actual pointer to
3579 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3580 * if (!is_ok (error)) { ... }
3582 * On failure sets \p error.
3585 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3587 MONO_REQ_GC_NEUTRAL_MODE;
3589 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3593 * mono_property_set_value:
3594 * \param prop MonoProperty to set
3595 * \param obj instance object on which to act
3596 * \param params parameters to pass to the propery
3597 * \param exc optional exception
3598 * Invokes the property's set method with the given arguments on the
3599 * object instance obj (or NULL for static properties).
3601 * You can pass NULL as the exc argument if you don't want to
3602 * catch exceptions, otherwise, \c *exc will be set to the exception
3603 * thrown, if any. if an exception is thrown, you can't use the
3604 * \c MonoObject* result from the function.
3607 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3609 MONO_REQ_GC_UNSAFE_MODE;
3612 do_runtime_invoke (prop->set, obj, params, exc, &error);
3613 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3614 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3616 mono_error_cleanup (&error);
3621 * mono_property_set_value_checked:
3622 * \param prop \c MonoProperty to set
3623 * \param obj instance object on which to act
3624 * \param params parameters to pass to the propery
3625 * \param error set on error
3626 * Invokes the property's set method with the given arguments on the
3627 * object instance \p obj (or NULL for static properties).
3628 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3629 * If an exception is thrown, it will be caught and returned via \p error.
3632 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3634 MONO_REQ_GC_UNSAFE_MODE;
3639 do_runtime_invoke (prop->set, obj, params, &exc, error);
3640 if (exc != NULL && is_ok (error))
3641 mono_error_set_exception_instance (error, (MonoException*)exc);
3642 return is_ok (error);
3646 * mono_property_get_value:
3647 * \param prop \c MonoProperty to fetch
3648 * \param obj instance object on which to act
3649 * \param params parameters to pass to the propery
3650 * \param exc optional exception
3651 * Invokes the property's \c get method with the given arguments on the
3652 * object instance \p obj (or NULL for static properties).
3654 * You can pass NULL as the \p exc argument if you don't want to
3655 * catch exceptions, otherwise, \c *exc will be set to the exception
3656 * thrown, if any. if an exception is thrown, you can't use the
3657 * \c MonoObject* result from the function.
3659 * \returns the value from invoking the \c get method on the property.
3662 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3664 MONO_REQ_GC_UNSAFE_MODE;
3667 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3668 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3669 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3671 mono_error_cleanup (&error); /* FIXME don't raise here */
3678 * mono_property_get_value_checked:
3679 * \param prop \c MonoProperty to fetch
3680 * \param obj instance object on which to act
3681 * \param params parameters to pass to the propery
3682 * \param error set on error
3683 * Invokes the property's \c get method with the given arguments on the
3684 * object instance obj (or NULL for static properties).
3686 * If an exception is thrown, you can't use the
3687 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3689 * \returns the value from invoking the get method on the property. On
3690 * failure returns NULL and sets \p error.
3693 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3695 MONO_REQ_GC_UNSAFE_MODE;
3698 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3699 if (exc != NULL && !is_ok (error))
3700 mono_error_set_exception_instance (error, (MonoException*) exc);
3708 * mono_nullable_init:
3709 * @buf: The nullable structure to initialize.
3710 * @value: the value to initialize from
3711 * @klass: the type for the object
3713 * Initialize the nullable structure pointed to by @buf from @value which
3714 * should be a boxed value type. The size of @buf should be able to hold
3715 * as much data as the @klass->instance_size (which is the number of bytes
3716 * that will be copies).
3718 * Since Nullables have variable structure, we can not define a C
3719 * structure for them.
3722 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3724 MONO_REQ_GC_UNSAFE_MODE;
3726 MonoClass *param_class = klass->cast_class;
3728 mono_class_setup_fields (klass);
3729 g_assert (klass->fields_inited);
3731 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3732 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3734 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3736 if (param_class->has_references)
3737 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3739 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3741 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3746 * mono_nullable_box:
3747 * \param buf The buffer representing the data to be boxed
3748 * \param klass the type to box it as.
3749 * \param error set on error
3751 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3752 * \p buf. On failure returns NULL and sets \p error.
3755 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3757 MONO_REQ_GC_UNSAFE_MODE;
3760 MonoClass *param_class = klass->cast_class;
3762 mono_class_setup_fields (klass);
3763 g_assert (klass->fields_inited);
3765 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3766 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3768 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3769 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3770 return_val_if_nok (error, NULL);
3771 if (param_class->has_references)
3772 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3774 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3782 * mono_get_delegate_invoke:
3783 * \param klass The delegate class
3784 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3787 mono_get_delegate_invoke (MonoClass *klass)
3789 MONO_REQ_GC_NEUTRAL_MODE;
3793 /* This is called at runtime, so avoid the slower search in metadata */
3794 mono_class_setup_methods (klass);
3795 if (mono_class_has_failure (klass))
3797 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3802 * mono_get_delegate_begin_invoke:
3803 * \param klass The delegate class
3804 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3807 mono_get_delegate_begin_invoke (MonoClass *klass)
3809 MONO_REQ_GC_NEUTRAL_MODE;
3813 /* This is called at runtime, so avoid the slower search in metadata */
3814 mono_class_setup_methods (klass);
3815 if (mono_class_has_failure (klass))
3817 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3822 * mono_get_delegate_end_invoke:
3823 * \param klass The delegate class
3824 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3827 mono_get_delegate_end_invoke (MonoClass *klass)
3829 MONO_REQ_GC_NEUTRAL_MODE;
3833 /* This is called at runtime, so avoid the slower search in metadata */
3834 mono_class_setup_methods (klass);
3835 if (mono_class_has_failure (klass))
3837 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3842 * mono_runtime_delegate_invoke:
3843 * \param delegate pointer to a delegate object.
3844 * \param params parameters for the delegate.
3845 * \param exc Pointer to the exception result.
3847 * Invokes the delegate method \p delegate with the parameters provided.
3849 * You can pass NULL as the \p exc argument if you don't want to
3850 * catch exceptions, otherwise, \c *exc will be set to the exception
3851 * thrown, if any. if an exception is thrown, you can't use the
3852 * \c MonoObject* result from the function.
3855 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3857 MONO_REQ_GC_UNSAFE_MODE;
3861 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3863 mono_error_cleanup (&error);
3866 if (!is_ok (&error))
3867 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3871 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3872 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3878 * mono_runtime_delegate_try_invoke:
3879 * \param delegate pointer to a delegate object.
3880 * \param params parameters for the delegate.
3881 * \param exc Pointer to the exception result.
3882 * \param error set on error
3883 * Invokes the delegate method \p delegate with the parameters provided.
3885 * You can pass NULL as the \p exc argument if you don't want to
3886 * catch exceptions, otherwise, \c *exc will be set to the exception
3887 * thrown, if any. On failure to execute, \p error will be set.
3888 * if an exception is thrown, you can't use the
3889 * \c MonoObject* result from the function.
3892 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3894 MONO_REQ_GC_UNSAFE_MODE;
3898 MonoClass *klass = delegate->vtable->klass;
3901 im = mono_get_delegate_invoke (klass);
3903 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3906 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3908 o = mono_runtime_invoke_checked (im, delegate, params, error);
3915 * mono_runtime_delegate_invoke_checked:
3916 * \param delegate pointer to a delegate object.
3917 * \param params parameters for the delegate.
3918 * \param error set on error
3919 * Invokes the delegate method \p delegate with the parameters provided.
3920 * On failure \p error will be set and you can't use the \c MonoObject*
3921 * result from the function.
3924 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3927 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3930 static char **main_args = NULL;
3931 static int num_main_args = 0;
3934 * mono_runtime_get_main_args:
3936 * Returns: a MonoArray with the arguments passed to the main program
3939 mono_runtime_get_main_args (void)
3941 MONO_REQ_GC_UNSAFE_MODE;
3943 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3944 mono_error_assert_ok (&error);
3949 * mono_runtime_get_main_args_checked:
3950 * \param error set on error
3951 * \returns a \c MonoArray with the arguments passed to the main
3952 * program. On failure returns NULL and sets \p error.
3955 mono_runtime_get_main_args_checked (MonoError *error)
3959 MonoDomain *domain = mono_domain_get ();
3963 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3964 return_val_if_nok (error, NULL);
3966 for (i = 0; i < num_main_args; ++i)
3967 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3973 free_main_args (void)
3975 MONO_REQ_GC_NEUTRAL_MODE;
3979 for (i = 0; i < num_main_args; ++i)
3980 g_free (main_args [i]);
3987 * mono_runtime_set_main_args:
3988 * \param argc number of arguments from the command line
3989 * \param argv array of strings from the command line
3990 * Set the command line arguments from an embedding application that doesn't otherwise call
3991 * \c mono_runtime_run_main.
3994 mono_runtime_set_main_args (int argc, char* argv[])
3996 MONO_REQ_GC_NEUTRAL_MODE;
4001 main_args = g_new0 (char*, argc);
4002 num_main_args = argc;
4004 for (i = 0; i < argc; ++i) {
4007 utf8_arg = mono_utf8_from_external (argv[i]);
4008 if (utf8_arg == NULL) {
4009 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4010 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4014 main_args [i] = utf8_arg;
4021 * Prepare an array of arguments in order to execute a standard Main()
4022 * method (argc/argv contains the executable name). This method also
4023 * sets the command line argument value needed by System.Environment.
4027 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4029 MONO_REQ_GC_UNSAFE_MODE;
4033 MonoArray *args = NULL;
4034 MonoDomain *domain = mono_domain_get ();
4035 gchar *utf8_fullpath;
4036 MonoMethodSignature *sig;
4038 g_assert (method != NULL);
4040 mono_thread_set_main (mono_thread_current ());
4042 main_args = g_new0 (char*, argc);
4043 num_main_args = argc;
4045 if (!g_path_is_absolute (argv [0])) {
4046 gchar *basename = g_path_get_basename (argv [0]);
4047 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4051 utf8_fullpath = mono_utf8_from_external (fullpath);
4052 if(utf8_fullpath == NULL) {
4053 /* Printing the arg text will cause glib to
4054 * whinge about "Invalid UTF-8", but at least
4055 * its relevant, and shows the problem text
4058 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4059 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4066 utf8_fullpath = mono_utf8_from_external (argv[0]);
4067 if(utf8_fullpath == NULL) {
4068 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4069 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4074 main_args [0] = utf8_fullpath;
4076 for (i = 1; i < argc; ++i) {
4079 utf8_arg=mono_utf8_from_external (argv[i]);
4080 if(utf8_arg==NULL) {
4081 /* Ditto the comment about Invalid UTF-8 here */
4082 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4083 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4087 main_args [i] = utf8_arg;
4092 sig = mono_method_signature (method);
4094 g_print ("Unable to load Main method.\n");
4098 if (sig->param_count) {
4099 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4100 mono_error_assert_ok (&error);
4101 for (i = 0; i < argc; ++i) {
4102 /* The encodings should all work, given that
4103 * we've checked all these args for the
4106 gchar *str = mono_utf8_from_external (argv [i]);
4107 MonoString *arg = mono_string_new (domain, str);
4108 mono_array_setref (args, i, arg);
4112 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4113 mono_error_assert_ok (&error);
4116 mono_assembly_set_main (method->klass->image->assembly);
4122 * mono_runtime_run_main:
4123 * \param method the method to start the application with (usually \c Main)
4124 * \param argc number of arguments from the command line
4125 * \param argv array of strings from the command line
4126 * \param exc excetption results
4127 * Execute a standard \c Main method (\p argc / \p argv contains the
4128 * executable name). This method also sets the command line argument value
4129 * needed by \c System.Environment.
4132 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4135 MONO_REQ_GC_UNSAFE_MODE;
4138 MonoArray *args = prepare_run_main (method, argc, argv);
4141 res = mono_runtime_try_exec_main (method, args, exc);
4143 res = mono_runtime_exec_main_checked (method, args, &error);
4144 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4150 * mono_runtime_run_main_checked:
4151 * \param method the method to start the application with (usually \c Main)
4152 * \param argc number of arguments from the command line
4153 * \param argv array of strings from the command line
4154 * \param error set on error
4156 * Execute a standard \c Main method (\p argc / \p argv contains the
4157 * executable name). This method also sets the command line argument value
4158 * needed by \c System.Environment. On failure sets \p error.
4161 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4165 MonoArray *args = prepare_run_main (method, argc, argv);
4166 return mono_runtime_exec_main_checked (method, args, error);
4170 * mono_runtime_try_run_main:
4171 * \param method the method to start the application with (usually \c Main)
4172 * \param argc number of arguments from the command line
4173 * \param argv array of strings from the command line
4174 * \param exc set if \c Main throws an exception
4175 * \param error set if \c Main can't be executed
4176 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4177 * name). This method also sets the command line argument value needed
4178 * by \c System.Environment. On failure sets \p error if Main can't be
4179 * executed or \p exc if it threw an exception.
4182 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4186 MonoArray *args = prepare_run_main (method, argc, argv);
4187 return mono_runtime_try_exec_main (method, args, exc);
4192 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4194 static MonoMethod *serialize_method;
4200 if (!serialize_method) {
4201 MonoClass *klass = mono_class_get_remoting_services_class ();
4202 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4205 if (!serialize_method) {
4210 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4215 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4216 if (*exc == NULL && !mono_error_ok (&error))
4217 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4219 mono_error_cleanup (&error);
4228 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4230 MONO_REQ_GC_UNSAFE_MODE;
4232 static MonoMethod *deserialize_method;
4238 if (!deserialize_method) {
4239 MonoClass *klass = mono_class_get_remoting_services_class ();
4240 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4242 if (!deserialize_method) {
4250 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4251 if (*exc == NULL && !mono_error_ok (&error))
4252 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4254 mono_error_cleanup (&error);
4262 #ifndef DISABLE_REMOTING
4264 make_transparent_proxy (MonoObject *obj, MonoError *error)
4266 MONO_REQ_GC_UNSAFE_MODE;
4268 static MonoMethod *get_proxy_method;
4270 MonoDomain *domain = mono_domain_get ();
4271 MonoRealProxy *real_proxy;
4272 MonoReflectionType *reflection_type;
4273 MonoTransparentProxy *transparent_proxy;
4277 if (!get_proxy_method)
4278 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4280 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4282 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4283 return_val_if_nok (error, NULL);
4284 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4285 return_val_if_nok (error, NULL);
4287 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4288 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4290 MonoObject *exc = NULL;
4292 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4293 if (exc != NULL && is_ok (error))
4294 mono_error_set_exception_instance (error, (MonoException*)exc);
4296 return (MonoObject*) transparent_proxy;
4298 #endif /* DISABLE_REMOTING */
4301 * mono_object_xdomain_representation
4302 * \param obj an object
4303 * \param target_domain a domain
4304 * \param error set on error.
4305 * Creates a representation of obj in the domain \p target_domain. This
4306 * is either a copy of \p obj arrived through via serialization and
4307 * deserialization or a proxy, depending on whether the object is
4308 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4309 * If the object cannot be represented in \p target_domain, NULL is
4310 * returned and \p error is set appropriately.
4313 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4315 MONO_REQ_GC_UNSAFE_MODE;
4318 MonoObject *deserialized = NULL;
4320 #ifndef DISABLE_REMOTING
4321 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4322 deserialized = make_transparent_proxy (obj, error);
4327 gboolean failure = FALSE;
4328 MonoDomain *domain = mono_domain_get ();
4329 MonoObject *serialized;
4330 MonoObject *exc = NULL;
4332 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4333 serialized = serialize_object (obj, &failure, &exc);
4334 mono_domain_set_internal_with_options (target_domain, FALSE);
4336 deserialized = deserialize_object (serialized, &failure, &exc);
4337 if (domain != target_domain)
4338 mono_domain_set_internal_with_options (domain, FALSE);
4340 mono_error_set_exception_instance (error, (MonoException*)exc);
4343 return deserialized;
4346 /* Used in call_unhandled_exception_delegate */
4348 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4350 MONO_REQ_GC_UNSAFE_MODE;
4355 MonoMethod *method = NULL;
4356 MonoBoolean is_terminating = TRUE;
4359 klass = mono_class_get_unhandled_exception_event_args_class ();
4360 mono_class_init (klass);
4362 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4363 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4367 args [1] = &is_terminating;
4369 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4370 return_val_if_nok (error, NULL);
4372 mono_runtime_invoke_checked (method, obj, args, error);
4373 return_val_if_nok (error, NULL);
4378 /* Used in mono_unhandled_exception */
4380 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4381 MONO_REQ_GC_UNSAFE_MODE;
4384 MonoObject *e = NULL;
4386 MonoDomain *current_domain = mono_domain_get ();
4388 if (domain != current_domain)
4389 mono_domain_set_internal_with_options (domain, FALSE);
4391 g_assert (domain == mono_object_domain (domain->domain));
4393 if (mono_object_domain (exc) != domain) {
4395 exc = mono_object_xdomain_representation (exc, domain, &error);
4397 if (!is_ok (&error)) {
4398 MonoError inner_error;
4399 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4400 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4401 mono_error_assert_ok (&inner_error);
4403 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4404 "System.Runtime.Serialization", "SerializationException",
4405 "Could not serialize unhandled exception.");
4409 g_assert (mono_object_domain (exc) == domain);
4411 pa [0] = domain->domain;
4412 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4413 mono_error_assert_ok (&error);
4414 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4415 if (!is_ok (&error)) {
4417 e = (MonoObject*)mono_error_convert_to_exception (&error);
4419 mono_error_cleanup (&error);
4422 if (domain != current_domain)
4423 mono_domain_set_internal_with_options (current_domain, FALSE);
4426 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4427 if (!mono_error_ok (&error)) {
4428 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4429 mono_error_cleanup (&error);
4431 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4437 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4440 * mono_runtime_unhandled_exception_policy_set:
4441 * \param policy the new policy
4442 * This is a VM internal routine.
4443 * Sets the runtime policy for handling unhandled exceptions.
4446 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4447 runtime_unhandled_exception_policy = policy;
4451 * mono_runtime_unhandled_exception_policy_get:
4453 * This is a VM internal routine.
4455 * Gets the runtime policy for handling unhandled exceptions.
4457 MonoRuntimeUnhandledExceptionPolicy
4458 mono_runtime_unhandled_exception_policy_get (void) {
4459 return runtime_unhandled_exception_policy;
4463 * mono_unhandled_exception:
4464 * \param exc exception thrown
4465 * This is a VM internal routine.
4467 * We call this function when we detect an unhandled exception
4468 * in the default domain.
4470 * It invokes the \c UnhandledException event in \c AppDomain or prints
4471 * a warning to the console
4474 mono_unhandled_exception (MonoObject *exc)
4476 MONO_REQ_GC_UNSAFE_MODE;
4479 MonoClassField *field;
4480 MonoDomain *current_domain, *root_domain;
4481 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4483 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4486 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4489 current_domain = mono_domain_get ();
4490 root_domain = mono_get_root_domain ();
4492 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4493 mono_error_assert_ok (&error);
4494 if (current_domain != root_domain) {
4495 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4496 mono_error_assert_ok (&error);
4499 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4500 mono_print_unhandled_exception (exc);
4502 /* unhandled exception callbacks must not be aborted */
4503 mono_threads_begin_abort_protected_block ();
4504 if (root_appdomain_delegate)
4505 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4506 if (current_appdomain_delegate)
4507 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4508 mono_threads_end_abort_protected_block ();
4511 /* set exitcode only if we will abort the process */
4512 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4513 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4515 mono_environment_exitcode_set (1);
4520 * mono_runtime_exec_managed_code:
4521 * \param domain Application domain
4522 * \param main_func function to invoke from the execution thread
4523 * \param main_args parameter to the main_func
4524 * Launch a new thread to execute a function
4526 * \p main_func is called back from the thread with main_args as the
4527 * parameter. The callback function is expected to start \c Main
4528 * eventually. This function then waits for all managed threads to
4530 * It is not necessary anymore to execute managed code in a subthread,
4531 * so this function should not be used anymore by default: just
4532 * execute the code and then call mono_thread_manage().
4535 mono_runtime_exec_managed_code (MonoDomain *domain,
4536 MonoMainThreadFunc main_func,
4540 mono_thread_create_checked (domain, main_func, main_args, &error);
4541 mono_error_assert_ok (&error);
4543 mono_thread_manage ();
4547 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4549 MonoInternalThread* thread = mono_thread_internal_current ();
4550 MonoCustomAttrInfo* cinfo;
4551 gboolean has_stathread_attribute;
4553 if (!domain->entry_assembly) {
4555 MonoAssembly *assembly;
4557 assembly = method->klass->image->assembly;
4558 domain->entry_assembly = assembly;
4559 /* Domains created from another domain already have application_base and configuration_file set */
4560 if (domain->setup->application_base == NULL) {
4561 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4564 if (domain->setup->configuration_file == NULL) {
4565 str = g_strconcat (assembly->image->name, ".config", NULL);
4566 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4568 mono_domain_set_options_from_config (domain);
4572 MonoError cattr_error;
4573 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4574 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4576 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4578 mono_custom_attrs_free (cinfo);
4580 has_stathread_attribute = FALSE;
4582 if (has_stathread_attribute) {
4583 thread->apartment_state = ThreadApartmentState_STA;
4585 thread->apartment_state = ThreadApartmentState_MTA;
4587 mono_thread_init_apartment_state ();
4592 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4594 MONO_REQ_GC_UNSAFE_MODE;
4604 /* FIXME: check signature of method */
4605 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4607 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4609 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4612 mono_environment_exitcode_set (rval);
4614 mono_runtime_invoke_checked (method, NULL, pa, error);
4626 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4628 MONO_REQ_GC_UNSAFE_MODE;
4638 /* FIXME: check signature of method */
4639 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4640 MonoError inner_error;
4642 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4643 if (*exc == NULL && !mono_error_ok (&inner_error))
4644 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4646 mono_error_cleanup (&inner_error);
4649 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4653 mono_environment_exitcode_set (rval);
4655 MonoError inner_error;
4656 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4657 if (*exc == NULL && !mono_error_ok (&inner_error))
4658 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4660 mono_error_cleanup (&inner_error);
4665 /* If the return type of Main is void, only
4666 * set the exitcode if an exception was thrown
4667 * (we don't want to blow away an
4668 * explicitly-set exit code)
4671 mono_environment_exitcode_set (rval);
4679 * Execute a standard Main() method (args doesn't contain the
4683 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4686 prepare_thread_to_exec_main (mono_object_domain (args), method);
4688 int rval = do_try_exec_main (method, args, exc);
4691 int rval = do_exec_main_checked (method, args, &error);
4692 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4698 * Execute a standard Main() method (args doesn't contain the
4701 * On failure sets @error
4704 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4707 prepare_thread_to_exec_main (mono_object_domain (args), method);
4708 return do_exec_main_checked (method, args, error);
4712 * Execute a standard Main() method (args doesn't contain the
4715 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4718 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4720 prepare_thread_to_exec_main (mono_object_domain (args), method);
4721 return do_try_exec_main (method, args, exc);
4726 /** invoke_array_extract_argument:
4727 * @params: array of arguments to the method.
4728 * @i: the index of the argument to extract.
4729 * @t: ith type from the method signature.
4730 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4731 * @error: set on error.
4733 * Given an array of method arguments, return the ith one using the corresponding type
4734 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4736 * On failure sets @error and returns NULL.
4739 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4741 MonoType *t_orig = t;
4742 gpointer result = NULL;
4748 case MONO_TYPE_BOOLEAN:
4751 case MONO_TYPE_CHAR:
4760 case MONO_TYPE_VALUETYPE:
4761 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4762 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4763 result = mono_array_get (params, MonoObject*, i);
4765 *has_byref_nullables = TRUE;
4767 /* MS seems to create the objects if a null is passed in */
4768 gboolean was_null = FALSE;
4769 if (!mono_array_get (params, MonoObject*, i)) {
4770 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4771 return_val_if_nok (error, NULL);
4772 mono_array_setref (params, i, o);
4778 * We can't pass the unboxed vtype byref to the callee, since
4779 * that would mean the callee would be able to modify boxed
4780 * primitive types. So we (and MS) make a copy of the boxed
4781 * object, pass that to the callee, and replace the original
4782 * boxed object in the arg array with the copy.
4784 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4785 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4786 return_val_if_nok (error, NULL);
4787 mono_array_setref (params, i, copy);
4790 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4791 if (!t->byref && was_null)
4792 mono_array_setref (params, i, NULL);
4795 case MONO_TYPE_STRING:
4796 case MONO_TYPE_OBJECT:
4797 case MONO_TYPE_CLASS:
4798 case MONO_TYPE_ARRAY:
4799 case MONO_TYPE_SZARRAY:
4801 result = mono_array_addr (params, MonoObject*, i);
4802 // FIXME: I need to check this code path
4804 result = mono_array_get (params, MonoObject*, i);
4806 case MONO_TYPE_GENERICINST:
4808 t = &t->data.generic_class->container_class->this_arg;
4810 t = &t->data.generic_class->container_class->byval_arg;
4812 case MONO_TYPE_PTR: {
4815 /* The argument should be an IntPtr */
4816 arg = mono_array_get (params, MonoObject*, i);
4820 g_assert (arg->vtable->klass == mono_defaults.int_class);
4821 result = ((MonoIntPtr*)arg)->m_value;
4826 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4831 * mono_runtime_invoke_array:
4832 * \param method method to invoke
4833 * \param obj object instance
4834 * \param params arguments to the method
4835 * \param exc exception information.
4836 * Invokes the method represented by \p method on the object \p obj.
4838 * \p obj is the \c this pointer, it should be NULL for static
4839 * methods, a \c MonoObject* for object instances and a pointer to
4840 * the value type for value types.
4842 * The \p params array contains the arguments to the method with the
4843 * same convention: \c MonoObject* pointers for object instances and
4844 * pointers to the value type otherwise. The \c _invoke_array
4845 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4846 * in this case the value types are boxed inside the
4847 * respective reference representation.
4849 * From unmanaged code you'll usually use the
4850 * mono_runtime_invoke_checked() variant.
4852 * Note that this function doesn't handle virtual methods for
4853 * you, it will exec the exact method you pass: we still need to
4854 * expose a function to lookup the derived class implementation
4855 * of a virtual method (there are examples of this in the code,
4858 * You can pass NULL as the \p exc argument if you don't want to
4859 * catch exceptions, otherwise, \c *exc will be set to the exception
4860 * thrown, if any. if an exception is thrown, you can't use the
4861 * \c MonoObject* result from the function.
4863 * If the method returns a value type, it is boxed in an object
4867 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4872 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4874 mono_error_cleanup (&error);
4877 if (!is_ok (&error))
4878 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4882 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4883 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4889 * mono_runtime_invoke_array_checked:
4890 * \param method method to invoke
4891 * \param obj object instance
4892 * \param params arguments to the method
4893 * \param error set on failure.
4894 * Invokes the method represented by \p method on the object \p obj.
4896 * \p obj is the \c this pointer, it should be NULL for static
4897 * methods, a \c MonoObject* for object instances and a pointer to
4898 * the value type for value types.
4900 * The \p params array contains the arguments to the method with the
4901 * same convention: \c MonoObject* pointers for object instances and
4902 * pointers to the value type otherwise. The \c _invoke_array
4903 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4904 * in this case the value types are boxed inside the
4905 * respective reference representation.
4907 * From unmanaged code you'll usually use the
4908 * mono_runtime_invoke_checked() variant.
4910 * Note that this function doesn't handle virtual methods for
4911 * you, it will exec the exact method you pass: we still need to
4912 * expose a function to lookup the derived class implementation
4913 * of a virtual method (there are examples of this in the code,
4916 * On failure or exception, \p error will be set. In that case, you
4917 * can't use the \c MonoObject* result from the function.
4919 * If the method returns a value type, it is boxed in an object
4923 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4927 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4931 * mono_runtime_try_invoke_array:
4932 * \param method method to invoke
4933 * \param obj object instance
4934 * \param params arguments to the method
4935 * \param exc exception information.
4936 * \param error set on failure.
4937 * Invokes the method represented by \p method on the object \p obj.
4939 * \p obj is the \c this pointer, it should be NULL for static
4940 * methods, a \c MonoObject* for object instances and a pointer to
4941 * the value type for value types.
4943 * The \p params array contains the arguments to the method with the
4944 * same convention: \c MonoObject* pointers for object instances and
4945 * pointers to the value type otherwise. The \c _invoke_array
4946 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4947 * 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 * You can pass NULL as the \p exc argument if you don't want to catch
4960 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
4961 * any. On other failures, \p error will be set. If an exception is
4962 * thrown or there's an error, you can't use the \c MonoObject* result
4963 * from the function.
4965 * If the method returns a value type, it is boxed in an object
4969 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4970 MonoObject **exc, MonoError *error)
4972 MONO_REQ_GC_UNSAFE_MODE;
4976 MonoMethodSignature *sig = mono_method_signature (method);
4977 gpointer *pa = NULL;
4980 gboolean has_byref_nullables = FALSE;
4982 if (NULL != params) {
4983 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4984 for (i = 0; i < mono_array_length (params); i++) {
4985 MonoType *t = sig->params [i];
4986 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4987 return_val_if_nok (error, NULL);
4991 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4994 if (mono_class_is_nullable (method->klass)) {
4995 /* Need to create a boxed vtype instead */
5001 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5006 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5007 mono_error_assert_ok (error);
5008 g_assert (obj); /*maybe we should raise a TLE instead?*/
5009 #ifndef DISABLE_REMOTING
5010 if (mono_object_is_transparent_proxy (obj)) {
5011 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5014 if (method->klass->valuetype)
5015 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5018 } else if (method->klass->valuetype) {
5019 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5020 return_val_if_nok (error, NULL);
5024 mono_runtime_try_invoke (method, o, pa, exc, error);
5026 mono_runtime_invoke_checked (method, o, pa, error);
5029 return (MonoObject *)obj;
5031 if (mono_class_is_nullable (method->klass)) {
5032 MonoObject *nullable;
5034 /* Convert the unboxed vtype into a Nullable structure */
5035 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5036 return_val_if_nok (error, NULL);
5038 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5039 return_val_if_nok (error, NULL);
5040 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5041 obj = mono_object_unbox (nullable);
5044 /* obj must be already unboxed if needed */
5046 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5048 res = mono_runtime_invoke_checked (method, obj, pa, error);
5050 return_val_if_nok (error, NULL);
5052 if (sig->ret->type == MONO_TYPE_PTR) {
5053 MonoClass *pointer_class;
5054 static MonoMethod *box_method;
5056 MonoObject *box_exc;
5059 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5060 * convert it to a Pointer object.
5062 pointer_class = mono_class_get_pointer_class ();
5064 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5066 g_assert (res->vtable->klass == mono_defaults.int_class);
5067 box_args [0] = ((MonoIntPtr*)res)->m_value;
5068 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5069 return_val_if_nok (error, NULL);
5071 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5072 g_assert (box_exc == NULL);
5073 mono_error_assert_ok (error);
5076 if (has_byref_nullables) {
5078 * The runtime invoke wrapper already converted byref nullables back,
5079 * and stored them in pa, we just need to copy them back to the
5082 for (i = 0; i < mono_array_length (params); i++) {
5083 MonoType *t = sig->params [i];
5085 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5086 mono_array_setref (params, i, pa [i]);
5096 * \param klass the class of the object that we want to create
5097 * \returns a newly created object whose definition is
5098 * looked up using \p klass. This will not invoke any constructors,
5099 * so the consumer of this routine has to invoke any constructors on
5100 * its own to initialize the object.
5102 * It returns NULL on failure.
5105 mono_object_new (MonoDomain *domain, MonoClass *klass)
5107 MONO_REQ_GC_UNSAFE_MODE;
5111 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5113 mono_error_cleanup (&error);
5118 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5120 MONO_REQ_GC_UNSAFE_MODE;
5124 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5126 mono_error_set_pending_exception (&error);
5131 * mono_object_new_checked:
5132 * \param klass the class of the object that we want to create
5133 * \param error set on error
5134 * \returns a newly created object whose definition is
5135 * looked up using \p klass. This will not invoke any constructors,
5136 * so the consumer of this routine has to invoke any constructors on
5137 * its own to initialize the object.
5139 * It returns NULL on failure and sets \p error.
5142 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5144 MONO_REQ_GC_UNSAFE_MODE;
5148 vtable = mono_class_vtable (domain, klass);
5149 g_assert (vtable); /* FIXME don't swallow the error */
5151 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5156 * mono_object_new_pinned:
5158 * Same as mono_object_new, but the returned object will be pinned.
5159 * For SGEN, these objects will only be freed at appdomain unload.
5162 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5164 MONO_REQ_GC_UNSAFE_MODE;
5170 vtable = mono_class_vtable (domain, klass);
5171 g_assert (vtable); /* FIXME don't swallow the error */
5173 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5175 if (G_UNLIKELY (!o))
5176 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5177 else if (G_UNLIKELY (vtable->klass->has_finalize))
5178 mono_object_register_finalizer (o);
5184 * mono_object_new_specific:
5185 * \param vtable the vtable of the object that we want to create
5186 * \returns A newly created object with class and domain specified
5190 mono_object_new_specific (MonoVTable *vtable)
5193 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5194 mono_error_cleanup (&error);
5200 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5202 MONO_REQ_GC_UNSAFE_MODE;
5208 /* check for is_com_object for COM Interop */
5209 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5212 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5215 MonoClass *klass = mono_class_get_activation_services_class ();
5218 mono_class_init (klass);
5220 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5222 mono_error_set_not_supported (error, "Linked away.");
5225 vtable->domain->create_proxy_for_type_method = im;
5228 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5229 if (!mono_error_ok (error))
5232 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5233 if (!mono_error_ok (error))
5240 return mono_object_new_alloc_specific_checked (vtable, error);
5244 ves_icall_object_new_specific (MonoVTable *vtable)
5247 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5248 mono_error_set_pending_exception (&error);
5254 * mono_object_new_alloc_specific:
5255 * \param vtable virtual table for the object.
5256 * This function allocates a new \c MonoObject with the type derived
5257 * from the \p vtable information. If the class of this object has a
5258 * finalizer, then the object will be tracked for finalization.
5260 * This method might raise an exception on errors. Use the
5261 * \c mono_object_new_fast_checked method if you want to manually raise
5264 * \returns the allocated object.
5267 mono_object_new_alloc_specific (MonoVTable *vtable)
5270 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5271 mono_error_cleanup (&error);
5277 * mono_object_new_alloc_specific_checked:
5278 * \param vtable virtual table for the object.
5279 * \param error holds the error return value.
5281 * This function allocates a new \c MonoObject with the type derived
5282 * from the \p vtable information. If the class of this object has a
5283 * finalizer, then the object will be tracked for finalization.
5285 * If there is not enough memory, the \p error parameter will be set
5286 * and will contain a user-visible message with the amount of bytes
5287 * that were requested.
5289 * \returns the allocated object, or NULL if there is not enough memory
5292 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5294 MONO_REQ_GC_UNSAFE_MODE;
5300 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5302 if (G_UNLIKELY (!o))
5303 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5304 else if (G_UNLIKELY (vtable->klass->has_finalize))
5305 mono_object_register_finalizer (o);
5311 * mono_object_new_fast:
5312 * \param vtable virtual table for the object.
5314 * This function allocates a new \c MonoObject with the type derived
5315 * from the \p vtable information. The returned object is not tracked
5316 * for finalization. If your object implements a finalizer, you should
5317 * use \c mono_object_new_alloc_specific instead.
5319 * This method might raise an exception on errors. Use the
5320 * \c mono_object_new_fast_checked method if you want to manually raise
5323 * \returns the allocated object.
5326 mono_object_new_fast (MonoVTable *vtable)
5329 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5330 mono_error_cleanup (&error);
5336 * mono_object_new_fast_checked:
5337 * \param vtable virtual table for the object.
5338 * \param error holds the error return value.
5340 * This function allocates a new \c MonoObject with the type derived
5341 * from the \p vtable information. The returned object is not tracked
5342 * for finalization. If your object implements a finalizer, you should
5343 * use \c mono_object_new_alloc_specific_checked instead.
5345 * If there is not enough memory, the \p error parameter will be set
5346 * and will contain a user-visible message with the amount of bytes
5347 * that were requested.
5349 * \returns the allocated object, or NULL if there is not enough memory
5352 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5354 MONO_REQ_GC_UNSAFE_MODE;
5360 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5362 if (G_UNLIKELY (!o))
5363 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5369 ves_icall_object_new_fast (MonoVTable *vtable)
5372 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5373 mono_error_set_pending_exception (&error);
5379 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5381 MONO_REQ_GC_UNSAFE_MODE;
5387 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5389 if (G_UNLIKELY (!o))
5390 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5391 else if (G_UNLIKELY (vtable->klass->has_finalize))
5392 mono_object_register_finalizer (o);
5398 * mono_class_get_allocation_ftn:
5399 * \param vtable vtable
5400 * \param for_box the object will be used for boxing
5401 * \param pass_size_in_words Unused
5402 * \returns the allocation function appropriate for the given class.
5405 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5407 MONO_REQ_GC_NEUTRAL_MODE;
5409 *pass_size_in_words = FALSE;
5411 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5412 return ves_icall_object_new_specific;
5414 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5416 return ves_icall_object_new_fast;
5419 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5420 * of the overhead of parameter passing.
5423 *pass_size_in_words = TRUE;
5424 #ifdef GC_REDIRECT_TO_LOCAL
5425 return GC_local_gcj_fast_malloc;
5427 return GC_gcj_fast_malloc;
5432 return ves_icall_object_new_specific;
5436 * mono_object_new_from_token:
5437 * \param image Context where the type_token is hosted
5438 * \param token a token of the type that we want to create
5439 * \returns A newly created object whose definition is
5440 * looked up using \p token in the \p image image
5443 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5445 MONO_REQ_GC_UNSAFE_MODE;
5451 klass = mono_class_get_checked (image, token, &error);
5452 mono_error_assert_ok (&error);
5454 result = mono_object_new_checked (domain, klass, &error);
5456 mono_error_cleanup (&error);
5463 * mono_object_clone:
5464 * \param obj the object to clone
5465 * \returns A newly created object who is a shallow copy of \p obj
5468 mono_object_clone (MonoObject *obj)
5471 MonoObject *o = mono_object_clone_checked (obj, &error);
5472 mono_error_cleanup (&error);
5478 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5480 MONO_REQ_GC_UNSAFE_MODE;
5487 size = obj->vtable->klass->instance_size;
5489 if (obj->vtable->klass->rank)
5490 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5492 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5494 if (G_UNLIKELY (!o)) {
5495 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5499 /* If the object doesn't contain references this will do a simple memmove. */
5500 mono_gc_wbarrier_object_copy (o, obj);
5502 if (obj->vtable->klass->has_finalize)
5503 mono_object_register_finalizer (o);
5508 * mono_array_full_copy:
5509 * \param src source array to copy
5510 * \param dest destination array
5511 * Copies the content of one array to another with exactly the same type and size.
5514 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5516 MONO_REQ_GC_UNSAFE_MODE;
5519 MonoClass *klass = src->obj.vtable->klass;
5521 g_assert (klass == dest->obj.vtable->klass);
5523 size = mono_array_length (src);
5524 g_assert (size == mono_array_length (dest));
5525 size *= mono_array_element_size (klass);
5527 array_full_copy_unchecked_size (src, dest, klass, size);
5531 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5534 if (klass->element_class->valuetype) {
5535 if (klass->element_class->has_references)
5536 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5538 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5540 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5543 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5548 * mono_array_clone_in_domain:
5549 * \param domain the domain in which the array will be cloned into
5550 * \param array the array to clone
5551 * \param error set on error
5552 * This routine returns a copy of the array that is hosted on the
5553 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5556 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5558 MONO_REQ_GC_UNSAFE_MODE;
5560 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5562 MonoClass *klass = mono_handle_class (array_handle);
5566 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5567 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5569 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5571 if (array_bounds == NULL) {
5572 size = mono_array_handle_length (array_handle);
5573 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5576 size *= mono_array_element_size (klass);
5578 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5579 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5580 size = mono_array_element_size (klass);
5581 for (int i = 0; i < klass->rank; ++i) {
5582 sizes [i] = array_bounds [i].length;
5583 size *= array_bounds [i].length;
5584 lower_bounds [i] = array_bounds [i].lower_bound;
5586 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5591 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5592 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5593 mono_gchandle_free (dst_handle);
5595 MONO_HANDLE_ASSIGN (result, o);
5598 mono_gchandle_free (src_handle);
5604 * \param array the array to clone
5605 * \returns A newly created array who is a shallow copy of \p array
5608 mono_array_clone (MonoArray *array)
5610 MONO_REQ_GC_UNSAFE_MODE;
5613 MonoArray *result = mono_array_clone_checked (array, &error);
5614 mono_error_cleanup (&error);
5619 * mono_array_clone_checked:
5620 * \param array the array to clone
5621 * \param error set on error
5622 * \returns A newly created array who is a shallow copy of \p array. On
5623 * failure returns NULL and sets \p error.
5626 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5628 MONO_REQ_GC_UNSAFE_MODE;
5629 HANDLE_FUNCTION_ENTER ();
5630 /* FIXME: callers of mono_array_clone_checked should use handles */
5632 MONO_HANDLE_DCL (MonoArray, array);
5633 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5634 HANDLE_FUNCTION_RETURN_OBJ (result);
5637 /* helper macros to check for overflow when calculating the size of arrays */
5638 #ifdef MONO_BIG_ARRAYS
5639 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5640 #define MYGUINT_MAX MYGUINT64_MAX
5641 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5642 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5643 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5644 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5645 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5647 #define MYGUINT32_MAX 4294967295U
5648 #define MYGUINT_MAX MYGUINT32_MAX
5649 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5650 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5651 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5652 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5653 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5657 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5659 MONO_REQ_GC_NEUTRAL_MODE;
5663 byte_len = mono_array_element_size (klass);
5664 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5667 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5669 byte_len += MONO_SIZEOF_MONO_ARRAY;
5677 * mono_array_new_full:
5678 * \param domain domain where the object is created
5679 * \param array_class array class
5680 * \param lengths lengths for each dimension in the array
5681 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5682 * This routine creates a new array object with the given dimensions,
5683 * lower bounds and type.
5686 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5689 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5690 mono_error_cleanup (&error);
5696 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5698 MONO_REQ_GC_UNSAFE_MODE;
5700 uintptr_t byte_len = 0, len, bounds_size;
5703 MonoArrayBounds *bounds;
5709 if (!array_class->inited)
5710 mono_class_init (array_class);
5714 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5715 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5717 if (len > MONO_ARRAY_MAX_INDEX) {
5718 mono_error_set_generic_error (error, "System", "OverflowException", "");
5723 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5725 for (i = 0; i < array_class->rank; ++i) {
5726 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5727 mono_error_set_generic_error (error, "System", "OverflowException", "");
5730 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5731 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5738 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5739 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5745 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5746 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5749 byte_len = (byte_len + 3) & ~3;
5750 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5751 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5754 byte_len += bounds_size;
5757 * Following three lines almost taken from mono_object_new ():
5758 * they need to be kept in sync.
5760 vtable = mono_class_vtable_full (domain, array_class, error);
5761 return_val_if_nok (error, NULL);
5764 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5766 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5768 if (G_UNLIKELY (!o)) {
5769 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5773 array = (MonoArray*)o;
5775 bounds = array->bounds;
5778 for (i = 0; i < array_class->rank; ++i) {
5779 bounds [i].length = lengths [i];
5781 bounds [i].lower_bound = lower_bounds [i];
5790 * \param domain domain where the object is created
5791 * \param eclass element class
5792 * \param n number of array elements
5793 * This routine creates a new szarray with \p n elements of type \p eclass.
5796 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5798 MONO_REQ_GC_UNSAFE_MODE;
5801 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5802 mono_error_cleanup (&error);
5807 * mono_array_new_checked:
5808 * \param domain domain where the object is created
5809 * \param eclass element class
5810 * \param n number of array elements
5811 * \param error set on error
5812 * This routine creates a new szarray with \p n elements of type \p eclass.
5813 * On failure returns NULL and sets \p error.
5816 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5822 ac = mono_array_class_get (eclass, 1);
5825 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5826 return_val_if_nok (error, NULL);
5828 return mono_array_new_specific_checked (vtable, n, error);
5832 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5835 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5836 mono_error_set_pending_exception (&error);
5842 * mono_array_new_specific:
5843 * \param vtable a vtable in the appropriate domain for an initialized class
5844 * \param n number of array elements
5845 * This routine is a fast alternative to \c mono_array_new for code which
5846 * can be sure about the domain it operates in.
5849 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5852 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5853 mono_error_cleanup (&error);
5859 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5861 MONO_REQ_GC_UNSAFE_MODE;
5868 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5869 mono_error_set_generic_error (error, "System", "OverflowException", "");
5873 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5874 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5877 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5879 if (G_UNLIKELY (!o)) {
5880 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5884 return (MonoArray*)o;
5888 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5891 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5892 mono_error_set_pending_exception (&error);
5898 * mono_string_empty_wrapper:
5900 * Returns: The same empty string instance as the managed string.Empty
5903 mono_string_empty_wrapper (void)
5905 MonoDomain *domain = mono_domain_get ();
5906 return mono_string_empty (domain);
5910 * mono_string_empty:
5912 * Returns: The same empty string instance as the managed string.Empty
5915 mono_string_empty (MonoDomain *domain)
5918 g_assert (domain->empty_string);
5919 return domain->empty_string;
5923 * mono_string_new_utf16:
5924 * \param text a pointer to an utf16 string
5925 * \param len the length of the string
5926 * \returns A newly created string object which contains \p text.
5929 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5931 MONO_REQ_GC_UNSAFE_MODE;
5934 MonoString *res = NULL;
5935 res = mono_string_new_utf16_checked (domain, text, len, &error);
5936 mono_error_cleanup (&error);
5942 * mono_string_new_utf16_checked:
5943 * \param text a pointer to an utf16 string
5944 * \param len the length of the string
5945 * \param error written on error.
5946 * \returns A newly created string object which contains \p text.
5947 * On error, returns NULL and sets \p error.
5950 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5952 MONO_REQ_GC_UNSAFE_MODE;
5958 s = mono_string_new_size_checked (domain, len, error);
5960 memcpy (mono_string_chars (s), text, len * 2);
5966 * mono_string_new_utf16_handle:
5967 * \param text a pointer to an utf16 string
5968 * \param len the length of the string
5969 * \param error written on error.
5970 * \returns A newly created string object which contains \p text.
5971 * On error, returns NULL and sets \p error.
5974 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5976 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
5980 * mono_string_new_utf32_checked:
5981 * \param text a pointer to an utf32 string
5982 * \param len the length of the string
5983 * \param error set on failure.
5984 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
5987 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5989 MONO_REQ_GC_UNSAFE_MODE;
5992 mono_unichar2 *utf16_output = NULL;
5993 gint32 utf16_len = 0;
5994 GError *gerror = NULL;
5995 glong items_written;
5998 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6001 g_error_free (gerror);
6003 while (utf16_output [utf16_len]) utf16_len++;
6005 s = mono_string_new_size_checked (domain, utf16_len, error);
6006 return_val_if_nok (error, NULL);
6008 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6010 g_free (utf16_output);
6016 * mono_string_new_utf32:
6017 * \param text a pointer to a UTF-32 string
6018 * \param len the length of the string
6019 * \returns A newly created string object which contains \p text.
6022 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6025 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6026 mono_error_cleanup (&error);
6031 * mono_string_new_size:
6032 * \param text a pointer to a UTF-16 string
6033 * \param len the length of the string
6034 * \returns A newly created string object of \p len
6037 mono_string_new_size (MonoDomain *domain, gint32 len)
6040 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6041 mono_error_cleanup (&error);
6047 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6049 MONO_REQ_GC_UNSAFE_MODE;
6057 /* check for overflow */
6058 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6059 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6063 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6064 g_assert (size > 0);
6066 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6069 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6071 if (G_UNLIKELY (!s)) {
6072 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6080 * mono_string_new_len:
6081 * \param text a pointer to an utf8 string
6082 * \param length number of bytes in \p text to consider
6083 * \returns A newly created string object which contains \p text.
6086 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6088 MONO_REQ_GC_UNSAFE_MODE;
6091 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6092 mono_error_cleanup (&error);
6097 * mono_string_new_len_checked:
6098 * \param text a pointer to an utf8 string
6099 * \param length number of bytes in \p text to consider
6100 * \param error set on error
6101 * \returns A newly created string object which contains \p text. On
6102 * failure returns NULL and sets \p error.
6105 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6107 MONO_REQ_GC_UNSAFE_MODE;
6111 GError *eg_error = NULL;
6112 MonoString *o = NULL;
6114 glong items_written;
6116 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6119 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6121 g_error_free (eg_error);
6130 * \param text a pointer to a UTF-8 string
6131 * \deprecated Use \c mono_string_new_checked in new code.
6132 * This function asserts if it cannot allocate a new string.
6133 * \returns A newly created string object which contains \p text.
6136 mono_string_new (MonoDomain *domain, const char *text)
6139 MonoString *res = NULL;
6140 res = mono_string_new_checked (domain, text, &error);
6141 mono_error_assert_ok (&error);
6146 * mono_string_new_checked:
6147 * \param text a pointer to an utf8 string
6148 * \param merror set on error
6149 * \returns A newly created string object which contains \p text.
6150 * On error returns NULL and sets \p merror.
6153 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6155 MONO_REQ_GC_UNSAFE_MODE;
6157 GError *eg_error = NULL;
6158 MonoString *o = NULL;
6160 glong items_written;
6167 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6170 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6172 g_error_free (eg_error);
6176 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6181 MonoString *o = NULL;
6183 if (!g_utf8_validate (text, -1, &end)) {
6184 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6188 len = g_utf8_strlen (text, -1);
6189 o = mono_string_new_size_checked (domain, len, error);
6192 str = mono_string_chars (o);
6194 while (text < end) {
6195 *str++ = g_utf8_get_char (text);
6196 text = g_utf8_next_char (text);
6205 * mono_string_new_wrapper:
6206 * \param text pointer to UTF-8 characters.
6207 * Helper function to create a string object from \p text in the current domain.
6210 mono_string_new_wrapper (const char *text)
6212 MONO_REQ_GC_UNSAFE_MODE;
6214 MonoDomain *domain = mono_domain_get ();
6217 return mono_string_new (domain, text);
6224 * \param class the class of the value
6225 * \param value a pointer to the unboxed data
6226 * \returns A newly created object which contains \p value.
6229 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6232 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6233 mono_error_cleanup (&error);
6238 * mono_value_box_checked:
6239 * \param domain the domain of the new object
6240 * \param class the class of the value
6241 * \param value a pointer to the unboxed data
6242 * \param error set on error
6243 * \returns A newly created object which contains \p value. On failure
6244 * returns NULL and sets \p error.
6247 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6249 MONO_REQ_GC_UNSAFE_MODE;
6256 g_assert (klass->valuetype);
6257 if (mono_class_is_nullable (klass))
6258 return mono_nullable_box ((guint8 *)value, klass, error);
6260 vtable = mono_class_vtable (domain, klass);
6263 size = mono_class_instance_size (klass);
6264 res = mono_object_new_alloc_specific_checked (vtable, error);
6265 return_val_if_nok (error, NULL);
6267 size = size - sizeof (MonoObject);
6270 g_assert (size == mono_class_value_size (klass, NULL));
6271 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6273 #if NO_UNALIGNED_ACCESS
6274 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6278 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6281 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6284 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6287 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6290 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6294 if (klass->has_finalize) {
6295 mono_object_register_finalizer (res);
6296 return_val_if_nok (error, NULL);
6303 * \param dest destination pointer
6304 * \param src source pointer
6305 * \param klass a valuetype class
6306 * Copy a valuetype from \p src to \p dest. This function must be used
6307 * when \p klass contains reference fields.
6310 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6312 MONO_REQ_GC_UNSAFE_MODE;
6314 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6318 * mono_value_copy_array:
6319 * \param dest destination array
6320 * \param dest_idx index in the \p dest array
6321 * \param src source pointer
6322 * \param count number of items
6323 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6324 * This function must be used when \p klass contains references fields.
6325 * Overlap is handled.
6328 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6330 MONO_REQ_GC_UNSAFE_MODE;
6332 int size = mono_array_element_size (dest->obj.vtable->klass);
6333 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6334 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6335 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6339 * mono_object_get_domain:
6340 * \param obj object to query
6341 * \returns the \c MonoDomain where the object is hosted
6344 mono_object_get_domain (MonoObject *obj)
6346 MONO_REQ_GC_UNSAFE_MODE;
6348 return mono_object_domain (obj);
6352 * mono_object_get_class:
6353 * \param obj object to query
6354 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6355 * \returns the \c MonoClass of the object.
6358 mono_object_get_class (MonoObject *obj)
6360 MONO_REQ_GC_UNSAFE_MODE;
6362 return mono_object_class (obj);
6365 * mono_object_get_size:
6366 * \param o object to query
6367 * \returns the size, in bytes, of \p o
6370 mono_object_get_size (MonoObject* o)
6372 MONO_REQ_GC_UNSAFE_MODE;
6374 MonoClass* klass = mono_object_class (o);
6375 if (klass == mono_defaults.string_class) {
6376 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6377 } else if (o->vtable->rank) {
6378 MonoArray *array = (MonoArray*)o;
6379 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6380 if (array->bounds) {
6383 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6387 return mono_class_instance_size (klass);
6392 * mono_object_unbox:
6393 * \param obj object to unbox
6394 * \returns a pointer to the start of the valuetype boxed in this
6397 * This method will assert if the object passed is not a valuetype.
6400 mono_object_unbox (MonoObject *obj)
6402 MONO_REQ_GC_UNSAFE_MODE;
6404 /* add assert for valuetypes? */
6405 g_assert (obj->vtable->klass->valuetype);
6406 return ((char*)obj) + sizeof (MonoObject);
6410 * mono_object_isinst:
6411 * \param obj an object
6412 * \param klass a pointer to a class
6413 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6416 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6418 MONO_REQ_GC_UNSAFE_MODE;
6420 HANDLE_FUNCTION_ENTER ();
6421 MONO_HANDLE_DCL (MonoObject, obj);
6423 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6424 mono_error_cleanup (&error);
6425 HANDLE_FUNCTION_RETURN_OBJ (result);
6430 * mono_object_isinst_checked:
6431 * \param obj an object
6432 * \param klass a pointer to a class
6433 * \param error set on error
6434 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6435 * On failure returns NULL and sets \p error.
6438 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6440 MONO_REQ_GC_UNSAFE_MODE;
6442 HANDLE_FUNCTION_ENTER ();
6444 MONO_HANDLE_DCL (MonoObject, obj);
6445 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6446 HANDLE_FUNCTION_RETURN_OBJ (result);
6450 * mono_object_handle_isinst:
6451 * \param obj an object
6452 * \param klass a pointer to a class
6453 * \param error set on error
6454 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6455 * On failure returns NULL and sets \p error.
6458 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6463 mono_class_init (klass);
6465 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6466 return mono_object_handle_isinst_mbyref (obj, klass, error);
6469 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6471 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6472 MONO_HANDLE_ASSIGN (result, obj);
6477 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6479 MONO_REQ_GC_UNSAFE_MODE;
6481 HANDLE_FUNCTION_ENTER ();
6483 MONO_HANDLE_DCL (MonoObject, obj);
6484 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6485 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6486 HANDLE_FUNCTION_RETURN_OBJ (result);
6490 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6494 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6496 if (MONO_HANDLE_IS_NULL (obj))
6499 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6501 if (mono_class_is_interface (klass)) {
6502 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6503 MONO_HANDLE_ASSIGN (result, obj);
6507 /* casting an array one of the invariant interfaces that must act as such */
6508 if (klass->is_array_special_interface) {
6509 if (mono_class_is_assignable_from (klass, vt->klass)) {
6510 MONO_HANDLE_ASSIGN (result, obj);
6515 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6516 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6517 MONO_HANDLE_ASSIGN (result, obj);
6521 MonoClass *oklass = vt->klass;
6522 if (mono_class_is_transparent_proxy (oklass)){
6523 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6524 oklass = remote_class->proxy_class;
6527 mono_class_setup_supertypes (klass);
6528 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6529 MONO_HANDLE_ASSIGN (result, obj);
6533 #ifndef DISABLE_REMOTING
6534 if (mono_class_is_transparent_proxy (vt->klass))
6536 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6537 if (!custom_type_info)
6539 MonoDomain *domain = mono_domain_get ();
6540 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6541 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6542 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6543 MonoMethod *im = NULL;
6546 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6548 mono_error_set_not_supported (error, "Linked away.");
6551 im = mono_object_handle_get_virtual_method (rp, im, error);
6556 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6560 pa [0] = MONO_HANDLE_RAW (reftype);
6561 pa [1] = MONO_HANDLE_RAW (obj);
6562 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6566 if (*(MonoBoolean *) mono_object_unbox(res)) {
6567 /* Update the vtable of the remote type, so it can safely cast to this new type */
6568 mono_upgrade_remote_class (domain, obj, klass, error);
6571 MONO_HANDLE_ASSIGN (result, obj);
6574 #endif /* DISABLE_REMOTING */
6580 * mono_object_castclass_mbyref:
6581 * \param obj an object
6582 * \param klass a pointer to a class
6583 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6586 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6588 MONO_REQ_GC_UNSAFE_MODE;
6589 HANDLE_FUNCTION_ENTER ();
6591 MONO_HANDLE_DCL (MonoObject, obj);
6592 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6593 if (MONO_HANDLE_IS_NULL (obj))
6595 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6596 mono_error_cleanup (&error);
6598 HANDLE_FUNCTION_RETURN_OBJ (result);
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;
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;
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 * \param o String to probe
6700 * \returns Whether the string has been interned.
6703 mono_string_is_interned (MonoString *o)
6706 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6707 /* This function does not fail. */
6708 mono_error_assert_ok (&error);
6713 * mono_string_intern:
6714 * \param o String to intern
6715 * Interns the string passed.
6716 * \returns The interned string.
6719 mono_string_intern (MonoString *str)
6722 MonoString *result = mono_string_intern_checked (str, &error);
6723 mono_error_assert_ok (&error);
6728 * mono_string_intern_checked:
6729 * \param o String to intern
6730 * \param error set on error.
6731 * Interns the string passed.
6732 * \returns The interned string. On failure returns NULL and sets \p error
6735 mono_string_intern_checked (MonoString *str, MonoError *error)
6737 MONO_REQ_GC_UNSAFE_MODE;
6741 return mono_string_is_interned_lookup (str, TRUE, error);
6746 * \param domain the domain where the string will be used.
6747 * \param image a metadata context
6748 * \param idx index into the user string table.
6749 * Implementation for the \c ldstr opcode.
6750 * \returns a loaded string from the \p image / \p idx combination.
6753 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6756 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6757 mono_error_cleanup (&error);
6762 * mono_ldstr_checked:
6763 * \param domain the domain where the string will be used.
6764 * \param image a metadata context
6765 * \param idx index into the user string table.
6766 * \param error set on error.
6767 * Implementation for the \c ldstr opcode.
6768 * \returns A loaded string from the \p image / \p idx combination.
6769 * On failure returns NULL and sets \p error.
6772 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6774 MONO_REQ_GC_UNSAFE_MODE;
6777 if (image->dynamic) {
6778 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6781 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6782 return NULL; /*FIXME we should probably be raising an exception here*/
6783 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6789 * mono_ldstr_metadata_sig
6790 * \param domain the domain for the string
6791 * \param sig the signature of a metadata string
6792 * \param error set on error
6793 * \returns a \c MonoString for a string stored in the metadata. On
6794 * failure returns NULL and sets \p error.
6797 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6799 MONO_REQ_GC_UNSAFE_MODE;
6802 const char *str = sig;
6803 MonoString *o, *interned;
6806 len2 = mono_metadata_decode_blob_size (str, &str);
6809 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6810 return_val_if_nok (error, NULL);
6811 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6814 guint16 *p2 = (guint16*)mono_string_chars (o);
6815 for (i = 0; i < len2; ++i) {
6816 *p2 = GUINT16_FROM_LE (*p2);
6822 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6825 return interned; /* o will get garbage collected */
6827 o = mono_string_get_pinned (o, error);
6830 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6832 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6844 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6848 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6854 GError *gerror = NULL;
6858 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6859 return NULL; /*FIXME we should probably be raising an exception here*/
6860 str = mono_metadata_user_string (image, idx);
6862 len2 = mono_metadata_decode_blob_size (str, &str);
6865 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6867 mono_error_set_argument (error, "string", "%s", gerror->message);
6868 g_error_free (gerror);
6871 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6872 if (len2 > written) {
6873 /* allocate the total length and copy the part of the string that has been converted */
6874 char *as2 = (char *)g_malloc0 (len2);
6875 memcpy (as2, as, written);
6884 * mono_string_to_utf8:
6885 * \param s a \c System.String
6886 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6887 * \returns the UTF-8 representation for \p s.
6888 * The resulting buffer needs to be freed with \c mono_free().
6891 mono_string_to_utf8 (MonoString *s)
6893 MONO_REQ_GC_UNSAFE_MODE;
6896 char *result = mono_string_to_utf8_checked (s, &error);
6898 if (!is_ok (&error)) {
6899 mono_error_cleanup (&error);
6906 * mono_string_to_utf8_checked:
6907 * \param s a \c System.String
6908 * \param error a \c MonoError.
6909 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6910 * \p error to determine whether the conversion was successful.
6911 * The resulting buffer should be freed with \c mono_free().
6914 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6916 MONO_REQ_GC_UNSAFE_MODE;
6920 GError *gerror = NULL;
6928 return g_strdup ("");
6930 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6932 mono_error_set_argument (error, "string", "%s", gerror->message);
6933 g_error_free (gerror);
6936 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6937 if (s->length > written) {
6938 /* allocate the total length and copy the part of the string that has been converted */
6939 char *as2 = (char *)g_malloc0 (s->length);
6940 memcpy (as2, as, written);
6949 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6951 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6955 * mono_string_to_utf8_ignore:
6956 * \param s a MonoString
6957 * Converts a \c MonoString to its UTF-8 representation. Will ignore
6958 * invalid surrogate pairs.
6959 * The resulting buffer should be freed with \c mono_free().
6962 mono_string_to_utf8_ignore (MonoString *s)
6964 MONO_REQ_GC_UNSAFE_MODE;
6973 return g_strdup ("");
6975 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6977 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6978 if (s->length > written) {
6979 /* allocate the total length and copy the part of the string that has been converted */
6980 char *as2 = (char *)g_malloc0 (s->length);
6981 memcpy (as2, as, written);
6990 * mono_string_to_utf8_image_ignore:
6991 * \param s a \c System.String
6992 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6995 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6997 MONO_REQ_GC_UNSAFE_MODE;
6999 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7003 * mono_string_to_utf8_mp_ignore:
7004 * \param s a \c System.String
7005 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7008 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7010 MONO_REQ_GC_UNSAFE_MODE;
7012 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7017 * mono_string_to_utf16:
7018 * \param s a \c MonoString
7019 * \returns a null-terminated array of the UTF-16 chars
7020 * contained in \param s. The result must be freed with \c g_free().
7021 * This is a temporary helper until our string implementation
7022 * is reworked to always include the null-terminating char.
7025 mono_string_to_utf16 (MonoString *s)
7027 MONO_REQ_GC_UNSAFE_MODE;
7034 as = (char *)g_malloc ((s->length * 2) + 2);
7035 as [(s->length * 2)] = '\0';
7036 as [(s->length * 2) + 1] = '\0';
7039 return (gunichar2 *)(as);
7042 memcpy (as, mono_string_chars(s), s->length * 2);
7043 return (gunichar2 *)(as);
7047 * mono_string_to_utf32:
7048 * \param s a \c MonoString
7049 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7050 * contained in \p s. The result must be freed with \c g_free().
7053 mono_string_to_utf32 (MonoString *s)
7055 MONO_REQ_GC_UNSAFE_MODE;
7057 mono_unichar4 *utf32_output = NULL;
7058 GError *error = NULL;
7059 glong items_written;
7064 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7067 g_error_free (error);
7069 return utf32_output;
7073 * mono_string_from_utf16:
7074 * \param data the UTF-16 string (LPWSTR) to convert
7075 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7076 * \returns a \c MonoString.
7079 mono_string_from_utf16 (gunichar2 *data)
7082 MonoString *result = mono_string_from_utf16_checked (data, &error);
7083 mono_error_cleanup (&error);
7088 * mono_string_from_utf16_checked:
7089 * \param data the UTF-16 string (LPWSTR) to convert
7090 * \param error set on error
7091 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7092 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7095 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7098 MONO_REQ_GC_UNSAFE_MODE;
7101 MonoDomain *domain = mono_domain_get ();
7107 while (data [len]) len++;
7109 return mono_string_new_utf16_checked (domain, data, len, error);
7113 * mono_string_from_utf32:
7114 * \param data the UTF-32 string (LPWSTR) to convert
7115 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7116 * \returns a \c MonoString.
7119 mono_string_from_utf32 (mono_unichar4 *data)
7122 MonoString *result = mono_string_from_utf32_checked (data, &error);
7123 mono_error_cleanup (&error);
7128 * mono_string_from_utf32_checked:
7129 * \param data the UTF-32 string (LPWSTR) to convert
7130 * \param error set on error
7131 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7132 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7135 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7137 MONO_REQ_GC_UNSAFE_MODE;
7140 MonoString* result = NULL;
7141 mono_unichar2 *utf16_output = NULL;
7142 GError *gerror = NULL;
7143 glong items_written;
7149 while (data [len]) len++;
7151 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7154 g_error_free (gerror);
7156 result = mono_string_from_utf16_checked (utf16_output, error);
7157 g_free (utf16_output);
7162 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7164 MONO_REQ_GC_UNSAFE_MODE;
7171 r = mono_string_to_utf8_ignore (s);
7173 r = mono_string_to_utf8_checked (s, error);
7174 if (!mono_error_ok (error))
7181 len = strlen (r) + 1;
7183 mp_s = (char *)mono_mempool_alloc (mp, len);
7185 mp_s = (char *)mono_image_alloc (image, len);
7187 memcpy (mp_s, r, len);
7195 * mono_string_to_utf8_image:
7196 * \param s a \c System.String
7197 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7200 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7202 MONO_REQ_GC_UNSAFE_MODE;
7204 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7208 * mono_string_to_utf8_mp:
7209 * \param s a \c System.String
7210 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7213 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7215 MONO_REQ_GC_UNSAFE_MODE;
7217 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7221 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7224 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7226 eh_callbacks = *cbs;
7229 MonoRuntimeExceptionHandlingCallbacks *
7230 mono_get_eh_callbacks (void)
7232 return &eh_callbacks;
7236 * mono_raise_exception:
7237 * \param ex exception object
7238 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7241 mono_raise_exception (MonoException *ex)
7243 MONO_REQ_GC_UNSAFE_MODE;
7246 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7247 * that will cause gcc to omit the function epilog, causing problems when
7248 * the JIT tries to walk the stack, since the return address on the stack
7249 * will point into the next function in the executable, not this one.
7251 eh_callbacks.mono_raise_exception (ex);
7255 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7257 MONO_REQ_GC_UNSAFE_MODE;
7259 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7263 * mono_wait_handle_new:
7264 * \param domain Domain where the object will be created
7265 * \param handle Handle for the wait handle
7266 * \param error set on error.
7267 * \returns A new \c MonoWaitHandle created in the given domain for the
7268 * given handle. On failure returns NULL and sets \p error.
7271 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7273 MONO_REQ_GC_UNSAFE_MODE;
7275 MonoWaitHandle *res;
7276 gpointer params [1];
7277 static MonoMethod *handle_set;
7280 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7281 return_val_if_nok (error, NULL);
7283 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7285 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7287 params [0] = &handle;
7289 mono_runtime_invoke_checked (handle_set, res, params, error);
7294 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7296 MONO_REQ_GC_UNSAFE_MODE;
7298 static MonoClassField *f_safe_handle = NULL;
7301 if (!f_safe_handle) {
7302 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7303 g_assert (f_safe_handle);
7306 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7312 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7314 MONO_REQ_GC_UNSAFE_MODE;
7316 RuntimeInvokeFunction runtime_invoke;
7320 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7321 MonoMethod *method = mono_get_context_capture_method ();
7322 MonoMethod *wrapper;
7325 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7326 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7327 return_val_if_nok (error, NULL);
7328 domain->capture_context_method = mono_compile_method_checked (method, error);
7329 return_val_if_nok (error, NULL);
7332 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7334 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7337 * mono_async_result_new:
7338 * \param domain domain where the object will be created.
7339 * \param handle wait handle.
7340 * \param state state to pass to AsyncResult
7341 * \param data C closure data.
7342 * \param error set on error.
7343 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7344 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7345 * On failure returns NULL and sets \p error.
7348 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7350 MONO_REQ_GC_UNSAFE_MODE;
7353 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7354 return_val_if_nok (error, NULL);
7355 MonoObject *context = mono_runtime_capture_context (domain, error);
7356 return_val_if_nok (error, NULL);
7357 /* we must capture the execution context from the original thread */
7359 MONO_OBJECT_SETREF (res, execution_context, context);
7360 /* note: result may be null if the flow is suppressed */
7363 res->data = (void **)data;
7364 MONO_OBJECT_SETREF (res, object_data, object_data);
7365 MONO_OBJECT_SETREF (res, async_state, state);
7366 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7367 return_val_if_nok (error, NULL);
7369 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7371 res->sync_completed = FALSE;
7372 res->completed = FALSE;
7378 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7380 MONO_REQ_GC_UNSAFE_MODE;
7387 g_assert (ares->async_delegate);
7389 ac = (MonoAsyncCall*) ares->object_data;
7391 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7392 if (mono_error_set_pending_exception (&error))
7395 gpointer wait_event = NULL;
7397 ac->msg->exc = NULL;
7399 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7401 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7402 mono_threads_begin_abort_protected_block ();
7404 if (!ac->msg->exc) {
7405 MonoException *ex = mono_error_convert_to_exception (&error);
7406 ac->msg->exc = (MonoObject *)ex;
7408 mono_error_cleanup (&error);
7411 MONO_OBJECT_SETREF (ac, res, res);
7413 mono_monitor_enter ((MonoObject*) ares);
7414 ares->completed = 1;
7416 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7417 mono_monitor_exit ((MonoObject*) ares);
7419 if (wait_event != NULL)
7420 mono_w32event_set (wait_event);
7422 error_init (&error); //the else branch would leave it in an undefined state
7424 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7426 mono_threads_end_abort_protected_block ();
7428 if (mono_error_set_pending_exception (&error))
7436 mono_message_init (MonoDomain *domain,
7437 MonoMethodMessage *this_obj,
7438 MonoReflectionMethod *method,
7439 MonoArray *out_args,
7442 MONO_REQ_GC_UNSAFE_MODE;
7444 static MonoMethod *init_message_method = NULL;
7446 if (!init_message_method) {
7447 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7448 g_assert (init_message_method != NULL);
7452 /* FIXME set domain instead? */
7453 g_assert (domain == mono_domain_get ());
7460 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7461 return is_ok (error);
7464 #ifndef DISABLE_REMOTING
7466 * mono_remoting_invoke:
7467 * \param real_proxy pointer to a \c RealProxy object
7468 * \param msg The \c MonoMethodMessage to execute
7469 * \param exc used to store exceptions
7470 * \param out_args used to store output arguments
7471 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7472 * \c IMessage interface and it is not trivial to extract results from there. So
7473 * we call an helper method \c PrivateInvoke instead of calling
7474 * \c RealProxy::Invoke() directly.
7475 * \returns the result object.
7478 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7480 MONO_REQ_GC_UNSAFE_MODE;
7483 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7490 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7493 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7495 mono_error_set_not_supported (error, "Linked away.");
7498 real_proxy->vtable->domain->private_invoke_method = im;
7501 pa [0] = real_proxy;
7506 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7507 return_val_if_nok (error, NULL);
7514 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7515 MonoObject **exc, MonoArray **out_args, MonoError *error)
7517 MONO_REQ_GC_UNSAFE_MODE;
7519 static MonoClass *object_array_klass;
7524 MonoMethodSignature *sig;
7526 int i, j, outarg_count = 0;
7528 #ifndef DISABLE_REMOTING
7529 if (target && mono_object_is_transparent_proxy (target)) {
7530 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7531 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7532 target = tp->rp->unwrapped_server;
7534 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7539 domain = mono_domain_get ();
7540 method = msg->method->method;
7541 sig = mono_method_signature (method);
7543 for (i = 0; i < sig->param_count; i++) {
7544 if (sig->params [i]->byref)
7548 if (!object_array_klass) {
7551 klass = mono_array_class_get (mono_defaults.object_class, 1);
7554 mono_memory_barrier ();
7555 object_array_klass = klass;
7558 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7559 return_val_if_nok (error, NULL);
7561 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7564 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7565 return_val_if_nok (error, NULL);
7567 for (i = 0, j = 0; i < sig->param_count; i++) {
7568 if (sig->params [i]->byref) {
7570 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7571 mono_array_setref (*out_args, j, arg);
7580 * prepare_to_string_method:
7582 * @target: Set to @obj or unboxed value if a valuetype
7584 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7587 prepare_to_string_method (MonoObject *obj, void **target)
7589 MONO_REQ_GC_UNSAFE_MODE;
7591 static MonoMethod *to_string = NULL;
7599 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7601 method = mono_object_get_virtual_method (obj, to_string);
7603 // Unbox value type if needed
7604 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7605 *target = mono_object_unbox (obj);
7611 * mono_object_to_string:
7612 * \param obj The object
7613 * \param exc Any exception thrown by \c ToString(). May be NULL.
7614 * \returns the result of calling \c ToString() on an object.
7617 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7620 MonoString *s = NULL;
7622 MonoMethod *method = prepare_to_string_method (obj, &target);
7624 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7625 if (*exc == NULL && !mono_error_ok (&error))
7626 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7628 mono_error_cleanup (&error);
7630 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7631 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7638 * mono_object_to_string_checked:
7639 * \param obj The object
7640 * \param error Set on error.
7641 * \returns the result of calling \c ToString() on an object. If the
7642 * method cannot be invoked or if it raises an exception, sets \p error
7646 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7650 MonoMethod *method = prepare_to_string_method (obj, &target);
7651 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7655 * mono_object_try_to_string:
7656 * \param obj The object
7657 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7658 * \param error Set if method cannot be invoked.
7659 * \returns the result of calling \c ToString() on an object. If the
7660 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7664 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7669 MonoMethod *method = prepare_to_string_method (obj, &target);
7670 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7676 get_native_backtrace (MonoException *exc_raw)
7678 HANDLE_FUNCTION_ENTER ();
7679 MONO_HANDLE_DCL(MonoException, exc);
7680 char * trace = mono_exception_handle_get_native_backtrace (exc);
7681 HANDLE_FUNCTION_RETURN_VAL (trace);
7685 * mono_print_unhandled_exception:
7686 * \param exc The exception
7687 * Prints the unhandled exception.
7690 mono_print_unhandled_exception (MonoObject *exc)
7692 MONO_REQ_GC_UNSAFE_MODE;
7695 char *message = (char*)"";
7696 gboolean free_message = FALSE;
7699 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7700 message = g_strdup ("OutOfMemoryException");
7701 free_message = TRUE;
7702 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7703 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7704 free_message = TRUE;
7707 if (((MonoException*)exc)->native_trace_ips) {
7708 message = get_native_backtrace ((MonoException*)exc);
7709 free_message = TRUE;
7711 MonoObject *other_exc = NULL;
7712 str = mono_object_try_to_string (exc, &other_exc, &error);
7713 if (other_exc == NULL && !is_ok (&error))
7714 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7716 mono_error_cleanup (&error);
7718 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7719 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7721 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7722 original_backtrace, nested_backtrace);
7724 g_free (original_backtrace);
7725 g_free (nested_backtrace);
7726 free_message = TRUE;
7728 message = mono_string_to_utf8_checked (str, &error);
7729 if (!mono_error_ok (&error)) {
7730 mono_error_cleanup (&error);
7731 message = (char *) "";
7733 free_message = TRUE;
7740 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7741 * exc->vtable->klass->name, message);
7743 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7750 * mono_delegate_ctor_with_method:
7751 * \param this pointer to an uninitialized delegate object
7752 * \param target target object
7753 * \param addr pointer to native code
7754 * \param method method
7755 * \param error set on error.
7756 * Initialize a delegate and sets a specific method, not the one
7757 * associated with \p addr. This is useful when sharing generic code.
7758 * In that case \p addr will most probably not be associated with the
7759 * correct instantiation of the method.
7760 * On failure returns FALSE and sets \p error.
7763 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7765 MONO_REQ_GC_UNSAFE_MODE;
7768 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7770 g_assert (this_obj);
7773 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7776 delegate->method = method;
7778 mono_stats.delegate_creations++;
7780 #ifndef DISABLE_REMOTING
7781 if (target && mono_object_is_transparent_proxy (target)) {
7783 method = mono_marshal_get_remoting_invoke (method);
7784 #ifdef ENABLE_INTERPRETER
7785 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7787 delegate->method_ptr = mono_compile_method_checked (method, error);
7788 return_val_if_nok (error, FALSE);
7789 MONO_OBJECT_SETREF (delegate, target, target);
7793 delegate->method_ptr = addr;
7794 MONO_OBJECT_SETREF (delegate, target, target);
7797 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7798 if (callbacks.init_delegate)
7799 callbacks.init_delegate (delegate);
7804 * mono_delegate_ctor:
7805 * \param this pointer to an uninitialized delegate object
7806 * \param target target object
7807 * \param addr pointer to native code
7808 * \param error set on error.
7809 * This is used to initialize a delegate.
7810 * On failure returns FALSE and sets \p error.
7813 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7815 MONO_REQ_GC_UNSAFE_MODE;
7818 MonoDomain *domain = mono_domain_get ();
7820 MonoMethod *method = NULL;
7824 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7826 if (!ji && domain != mono_get_root_domain ())
7827 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7829 method = mono_jit_info_get_method (ji);
7830 g_assert (!mono_class_is_gtd (method->klass));
7833 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7837 * mono_method_call_message_new:
7838 * \param method method to encapsulate
7839 * \param params parameters to the method
7840 * \param invoke optional, delegate invoke.
7841 * \param cb async callback delegate.
7842 * \param state state passed to the async callback.
7843 * \param error set on error.
7844 * Translates arguments pointers into a \c MonoMethodMessage.
7845 * On failure returns NULL and sets \p error.
7848 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7849 MonoDelegate **cb, MonoObject **state, MonoError *error)
7851 MONO_REQ_GC_UNSAFE_MODE;
7855 MonoDomain *domain = mono_domain_get ();
7856 MonoMethodSignature *sig = mono_method_signature (method);
7857 MonoMethodMessage *msg;
7860 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7861 return_val_if_nok (error, NULL);
7864 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7865 return_val_if_nok (error, NULL);
7866 mono_message_init (domain, msg, rm, NULL, error);
7867 return_val_if_nok (error, NULL);
7868 count = sig->param_count - 2;
7870 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7871 return_val_if_nok (error, NULL);
7872 mono_message_init (domain, msg, rm, NULL, error);
7873 return_val_if_nok (error, NULL);
7874 count = sig->param_count;
7877 for (i = 0; i < count; i++) {
7882 if (sig->params [i]->byref)
7883 vpos = *((gpointer *)params [i]);
7887 klass = mono_class_from_mono_type (sig->params [i]);
7889 if (klass->valuetype) {
7890 arg = mono_value_box_checked (domain, klass, vpos, error);
7891 return_val_if_nok (error, NULL);
7893 arg = *((MonoObject **)vpos);
7895 mono_array_setref (msg->args, i, arg);
7898 if (cb != NULL && state != NULL) {
7899 *cb = *((MonoDelegate **)params [i]);
7901 *state = *((MonoObject **)params [i]);
7908 * mono_method_return_message_restore:
7910 * Restore results from message based processing back to arguments pointers
7913 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7915 MONO_REQ_GC_UNSAFE_MODE;
7919 MonoMethodSignature *sig = mono_method_signature (method);
7920 int i, j, type, size, out_len;
7922 if (out_args == NULL)
7924 out_len = mono_array_length (out_args);
7928 for (i = 0, j = 0; i < sig->param_count; i++) {
7929 MonoType *pt = sig->params [i];
7934 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7938 arg = (char *)mono_array_get (out_args, gpointer, j);
7941 g_assert (type != MONO_TYPE_VOID);
7943 if (MONO_TYPE_IS_REFERENCE (pt)) {
7944 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7947 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7948 size = mono_class_value_size (klass, NULL);
7949 if (klass->has_references)
7950 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7952 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7954 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7955 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7964 #ifndef DISABLE_REMOTING
7967 * mono_load_remote_field:
7968 * \param this pointer to an object
7969 * \param klass klass of the object containing \p field
7970 * \param field the field to load
7971 * \param res a storage to store the result
7972 * This method is called by the runtime on attempts to load fields of
7973 * transparent proxy objects. \p this points to such TP, \p klass is the class of
7974 * the object containing \p field. \p res is a storage location which can be
7975 * used to store the result.
7976 * \returns an address pointing to the value of field.
7979 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7982 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7983 mono_error_cleanup (&error);
7988 * mono_load_remote_field_checked:
7989 * \param this pointer to an object
7990 * \param klass klass of the object containing \p field
7991 * \param field the field to load
7992 * \param res a storage to store the result
7993 * \param error set on error
7994 * This method is called by the runtime on attempts to load fields of
7995 * transparent proxy objects. \p this points to such TP, \p klass is the class of
7996 * the object containing \p field. \p res is a storage location which can be
7997 * used to store the result.
7998 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8001 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8003 MONO_REQ_GC_UNSAFE_MODE;
8005 static MonoMethod *getter = NULL;
8009 MonoDomain *domain = mono_domain_get ();
8010 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8011 MonoClass *field_class;
8012 MonoMethodMessage *msg;
8013 MonoArray *out_args;
8017 g_assert (mono_object_is_transparent_proxy (this_obj));
8018 g_assert (res != NULL);
8020 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8021 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8026 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8028 mono_error_set_not_supported (error, "Linked away.");
8033 field_class = mono_class_from_mono_type (field->type);
8035 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8036 return_val_if_nok (error, NULL);
8037 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8038 return_val_if_nok (error, NULL);
8039 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8040 return_val_if_nok (error, NULL);
8041 mono_message_init (domain, msg, rm, out_args, error);
8042 return_val_if_nok (error, NULL);
8044 full_name = mono_type_get_full_name (klass);
8045 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8046 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8049 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8050 return_val_if_nok (error, NULL);
8053 mono_error_set_exception_instance (error, (MonoException *)exc);
8057 if (mono_array_length (out_args) == 0)
8060 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8062 if (field_class->valuetype) {
8063 return ((char *)*res) + sizeof (MonoObject);
8069 * mono_load_remote_field_new:
8073 * Missing documentation.
8076 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8080 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8081 mono_error_cleanup (&error);
8086 * mono_load_remote_field_new_checked:
8087 * \param this pointer to an object
8088 * \param klass klass of the object containing \p field
8089 * \param field the field to load
8090 * \param error set on error.
8091 * This method is called by the runtime on attempts to load fields of
8092 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8093 * the object containing \p field.
8094 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8097 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8099 MONO_REQ_GC_UNSAFE_MODE;
8103 static MonoMethod *tp_load = NULL;
8105 g_assert (mono_object_is_transparent_proxy (this_obj));
8108 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8110 mono_error_set_not_supported (error, "Linked away.");
8115 /* MonoType *type = mono_class_get_type (klass); */
8121 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8125 * mono_store_remote_field:
8126 * \param this_obj pointer to an object
8127 * \param klass klass of the object containing \p field
8128 * \param field the field to load
8129 * \param val the value/object to store
8130 * This method is called by the runtime on attempts to store fields of
8131 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8132 * the object containing \p field. \p val is the new value to store in \p field.
8135 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8138 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8139 mono_error_cleanup (&error);
8143 * mono_store_remote_field_checked:
8144 * \param this_obj pointer to an object
8145 * \param klass klass of the object containing \p field
8146 * \param field the field to load
8147 * \param val the value/object to store
8148 * \param error set on error
8149 * This method is called by the runtime on attempts to store fields of
8150 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8151 * the object containing \p field. \p val is the new value to store in \p field.
8152 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8155 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8158 MONO_REQ_GC_UNSAFE_MODE;
8162 MonoDomain *domain = mono_domain_get ();
8163 MonoClass *field_class;
8166 g_assert (mono_object_is_transparent_proxy (this_obj));
8168 field_class = mono_class_from_mono_type (field->type);
8170 if (field_class->valuetype) {
8171 arg = mono_value_box_checked (domain, field_class, val, error);
8172 return_val_if_nok (error, FALSE);
8174 arg = *((MonoObject**)val);
8177 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8181 * mono_store_remote_field_new:
8186 * Missing documentation
8189 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8192 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8193 mono_error_cleanup (&error);
8197 * mono_store_remote_field_new_checked:
8203 * Missing documentation
8206 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8208 MONO_REQ_GC_UNSAFE_MODE;
8210 static MonoMethod *tp_store = NULL;
8214 g_assert (mono_object_is_transparent_proxy (this_obj));
8217 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8219 mono_error_set_not_supported (error, "Linked away.");
8229 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8230 return is_ok (error);
8235 * mono_create_ftnptr:
8237 * Given a function address, create a function descriptor for it.
8238 * This is only needed on some platforms.
8241 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8243 return callbacks.create_ftnptr (domain, addr);
8247 * mono_get_addr_from_ftnptr:
8249 * Given a pointer to a function descriptor, return the function address.
8250 * This is only needed on some platforms.
8253 mono_get_addr_from_ftnptr (gpointer descr)
8255 return callbacks.get_addr_from_ftnptr (descr);
8259 * mono_string_chars:
8260 * \param s a \c MonoString
8261 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8264 mono_string_chars (MonoString *s)
8266 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8272 * mono_string_length:
8273 * \param s MonoString
8274 * \returns the length in characters of the string
8277 mono_string_length (MonoString *s)
8279 MONO_REQ_GC_UNSAFE_MODE;
8285 * mono_string_handle_length:
8286 * \param s \c MonoString
8287 * \returns the length in characters of the string
8290 mono_string_handle_length (MonoStringHandle s)
8292 MONO_REQ_GC_UNSAFE_MODE;
8294 return MONO_HANDLE_GETVAL (s, length);
8299 * mono_array_length:
8300 * \param array a \c MonoArray*
8301 * \returns the total number of elements in the array. This works for
8302 * both vectors and multidimensional arrays.
8305 mono_array_length (MonoArray *array)
8307 MONO_REQ_GC_UNSAFE_MODE;
8309 return array->max_length;
8313 * mono_array_addr_with_size:
8314 * \param array a \c MonoArray*
8315 * \param size size of the array elements
8316 * \param idx index into the array
8317 * Use this function to obtain the address for the \p idx item on the
8318 * \p array containing elements of size \p size.
8320 * This method performs no bounds checking or type checking.
8321 * \returns the address of the \p idx element in the array.
8324 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8326 MONO_REQ_GC_UNSAFE_MODE;
8328 return ((char*)(array)->vector) + size * idx;
8333 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8335 MonoDomain *domain = mono_domain_get ();
8343 len = g_list_length (list);
8344 res = mono_array_new_checked (domain, eclass, len, error);
8345 return_val_if_nok (error, NULL);
8347 for (i = 0; list; list = list->next, i++)
8348 mono_array_set (res, gpointer, i, list->data);
8355 * The following section is purely to declare prototypes and
8356 * document the API, as these C files are processed by our
8362 * \param array array to alter
8363 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8364 * \param index index into the array
8365 * \param value value to set
8366 * Value Type version: This sets the \p index's element of the \p array
8367 * with elements of size sizeof(type) to the provided \p value.
8369 * This macro does not attempt to perform type checking or bounds checking.
8371 * Use this to set value types in a \c MonoArray.
8373 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8378 * mono_array_setref:
8379 * \param array array to alter
8380 * \param index index into the array
8381 * \param value value to set
8382 * Reference Type version: This sets the \p index's element of the
8383 * \p array with elements of size sizeof(type) to the provided \p value.
8385 * This macro does not attempt to perform type checking or bounds checking.
8387 * Use this to reference types in a \c MonoArray.
8389 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8395 * \param array array on which to operate on
8396 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8397 * \param index index into the array
8399 * Use this macro to retrieve the \p index element of an \p array and
8400 * extract the value assuming that the elements of the array match
8401 * the provided type value.
8403 * This method can be used with both arrays holding value types and
8404 * reference types. For reference types, the \p type parameter should
8405 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8407 * This macro does not attempt to perform type checking or bounds checking.
8409 * \returns The element at the \p index position in the \p array.
8411 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)