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 * \c 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 \c 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#: <code>public bool Equals (object obj);</code>
2995 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
2997 * The 1st (<code>this</code>) parameter must not be used with static methods:
2999 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3001 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3003 * The last argument must be a non-null \c MonoException* pointer.
3004 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3005 * exception has been thrown in managed code. Otherwise it will point
3006 * to the \c MonoException* caught by the thunk. In this case, the result of
3007 * the thunk is undefined:
3010 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3012 * MonoException *ex = NULL;
3014 * Equals func = mono_method_get_unmanaged_thunk (method);
3016 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3020 * // handle exception
3025 * The calling convention of the thunk matches the platform's default
3026 * convention. This means that under Windows, C declarations must
3027 * contain the \c __stdcall attribute:
3029 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3033 * Value type arguments and return values are treated as they were objects:
3035 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3036 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3038 * Arguments must be properly boxed upon trunk's invocation, while return
3039 * values must be unboxed.
3042 mono_method_get_unmanaged_thunk (MonoMethod *method)
3044 MONO_REQ_GC_NEUTRAL_MODE;
3045 MONO_REQ_API_ENTRYPOINT;
3050 g_assert (!mono_threads_is_coop_enabled ());
3052 MONO_ENTER_GC_UNSAFE;
3053 method = mono_marshal_get_thunk_invoke_wrapper (method);
3054 res = mono_compile_method_checked (method, &error);
3055 mono_error_cleanup (&error);
3056 MONO_EXIT_GC_UNSAFE;
3062 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3064 MONO_REQ_GC_UNSAFE_MODE;
3068 /* object fields cannot be byref, so we don't need a
3070 gpointer *p = (gpointer*)dest;
3077 case MONO_TYPE_BOOLEAN:
3079 case MONO_TYPE_U1: {
3080 guint8 *p = (guint8*)dest;
3081 *p = value ? *(guint8*)value : 0;
3086 case MONO_TYPE_CHAR: {
3087 guint16 *p = (guint16*)dest;
3088 *p = value ? *(guint16*)value : 0;
3091 #if SIZEOF_VOID_P == 4
3096 case MONO_TYPE_U4: {
3097 gint32 *p = (gint32*)dest;
3098 *p = value ? *(gint32*)value : 0;
3101 #if SIZEOF_VOID_P == 8
3106 case MONO_TYPE_U8: {
3107 gint64 *p = (gint64*)dest;
3108 *p = value ? *(gint64*)value : 0;
3111 case MONO_TYPE_R4: {
3112 float *p = (float*)dest;
3113 *p = value ? *(float*)value : 0;
3116 case MONO_TYPE_R8: {
3117 double *p = (double*)dest;
3118 *p = value ? *(double*)value : 0;
3121 case MONO_TYPE_STRING:
3122 case MONO_TYPE_SZARRAY:
3123 case MONO_TYPE_CLASS:
3124 case MONO_TYPE_OBJECT:
3125 case MONO_TYPE_ARRAY:
3126 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3128 case MONO_TYPE_FNPTR:
3129 case MONO_TYPE_PTR: {
3130 gpointer *p = (gpointer*)dest;
3131 *p = deref_pointer? *(gpointer*)value: value;
3134 case MONO_TYPE_VALUETYPE:
3135 /* note that 't' and 'type->type' can be different */
3136 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3137 t = mono_class_enum_basetype (type->data.klass)->type;
3140 MonoClass *klass = mono_class_from_mono_type (type);
3141 int size = mono_class_value_size (klass, NULL);
3143 mono_gc_bzero_atomic (dest, size);
3145 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3148 case MONO_TYPE_GENERICINST:
3149 t = type->data.generic_class->container_class->byval_arg.type;
3152 g_error ("got type %x", type->type);
3157 * mono_field_set_value:
3158 * \param obj Instance object
3159 * \param field \c MonoClassField describing the field to set
3160 * \param value The value to be set
3162 * Sets the value of the field described by \p field in the object instance \p obj
3163 * to the value passed in \p value. This method should only be used for instance
3164 * fields. For static fields, use mono_field_static_set_value().
3166 * The value must be in the native format of the field type.
3169 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3171 MONO_REQ_GC_UNSAFE_MODE;
3175 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3177 dest = (char*)obj + field->offset;
3178 mono_copy_value (field->type, dest, value, FALSE);
3182 * mono_field_static_set_value:
3183 * \param field \c MonoClassField describing the field to set
3184 * \param value The value to be set
3185 * Sets the value of the static field described by \p field
3186 * to the value passed in \p value.
3187 * The value must be in the native format of the field type.
3190 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3192 MONO_REQ_GC_UNSAFE_MODE;
3196 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3197 /* you cant set a constant! */
3198 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3200 if (field->offset == -1) {
3201 /* Special static */
3204 mono_domain_lock (vt->domain);
3205 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3206 mono_domain_unlock (vt->domain);
3207 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3209 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3211 mono_copy_value (field->type, dest, value, FALSE);
3215 * mono_vtable_get_static_field_data:
3217 * Internal use function: return a pointer to the memory holding the static fields
3218 * for a class or NULL if there are no static fields.
3219 * This is exported only for use by the debugger.
3222 mono_vtable_get_static_field_data (MonoVTable *vt)
3224 MONO_REQ_GC_NEUTRAL_MODE
3226 if (!vt->has_static_fields)
3228 return vt->vtable [vt->klass->vtable_size];
3232 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3234 MONO_REQ_GC_UNSAFE_MODE;
3238 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3239 if (field->offset == -1) {
3240 /* Special static */
3243 mono_domain_lock (vt->domain);
3244 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3245 mono_domain_unlock (vt->domain);
3246 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3248 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3251 src = (guint8*)obj + field->offset;
3258 * mono_field_get_value:
3259 * \param obj Object instance
3260 * \param field \c MonoClassField describing the field to fetch information from
3261 * \param value pointer to the location where the value will be stored
3262 * Use this routine to get the value of the field \p field in the object
3265 * The pointer provided by value must be of the field type, for reference
3266 * types this is a \c MonoObject*, for value types its the actual pointer to
3271 * mono_field_get_value (obj, int_field, &i);
3274 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3276 MONO_REQ_GC_UNSAFE_MODE;
3282 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3284 src = (char*)obj + field->offset;
3285 mono_copy_value (field->type, value, src, TRUE);
3289 * mono_field_get_value_object:
3290 * \param domain domain where the object will be created (if boxing)
3291 * \param field \c MonoClassField describing the field to fetch information from
3292 * \param obj The object instance for the field.
3293 * \returns a new \c MonoObject with the value from the given field. If the
3294 * field represents a value type, the value is boxed.
3297 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3300 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3301 mono_error_assert_ok (&error);
3306 * mono_field_get_value_object_checked:
3307 * \param domain domain where the object will be created (if boxing)
3308 * \param field \c MonoClassField describing the field to fetch information from
3309 * \param obj The object instance for the field.
3310 * \param error Set on error.
3311 * \returns a new \c MonoObject with the value from the given field. If the
3312 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3315 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3317 MONO_REQ_GC_UNSAFE_MODE;
3323 MonoVTable *vtable = NULL;
3325 gboolean is_static = FALSE;
3326 gboolean is_ref = FALSE;
3327 gboolean is_literal = FALSE;
3328 gboolean is_ptr = FALSE;
3329 MonoType *type = mono_field_get_type_checked (field, error);
3331 return_val_if_nok (error, NULL);
3333 switch (type->type) {
3334 case MONO_TYPE_STRING:
3335 case MONO_TYPE_OBJECT:
3336 case MONO_TYPE_CLASS:
3337 case MONO_TYPE_ARRAY:
3338 case MONO_TYPE_SZARRAY:
3343 case MONO_TYPE_BOOLEAN:
3346 case MONO_TYPE_CHAR:
3355 case MONO_TYPE_VALUETYPE:
3356 is_ref = type->byref;
3358 case MONO_TYPE_GENERICINST:
3359 is_ref = !mono_type_generic_inst_is_valuetype (type);
3365 g_error ("type 0x%x not handled in "
3366 "mono_field_get_value_object", type->type);
3370 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3373 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3377 vtable = mono_class_vtable_full (domain, field->parent, error);
3378 return_val_if_nok (error, NULL);
3380 if (!vtable->initialized) {
3381 mono_runtime_class_init_full (vtable, error);
3382 return_val_if_nok (error, NULL);
3391 get_default_field_value (domain, field, &o, error);
3392 return_val_if_nok (error, NULL);
3393 } else if (is_static) {
3394 mono_field_static_get_value_checked (vtable, field, &o, error);
3395 return_val_if_nok (error, NULL);
3397 mono_field_get_value (obj, field, &o);
3403 static MonoMethod *m;
3409 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3410 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3416 get_default_field_value (domain, field, v, error);
3417 return_val_if_nok (error, NULL);
3418 } else if (is_static) {
3419 mono_field_static_get_value_checked (vtable, field, v, error);
3420 return_val_if_nok (error, NULL);
3422 mono_field_get_value (obj, field, v);
3425 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3426 args [0] = ptr ? *ptr : NULL;
3427 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3428 return_val_if_nok (error, NULL);
3430 o = mono_runtime_invoke_checked (m, NULL, args, error);
3431 return_val_if_nok (error, NULL);
3436 /* boxed value type */
3437 klass = mono_class_from_mono_type (type);
3439 if (mono_class_is_nullable (klass))
3440 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3442 o = mono_object_new_checked (domain, klass, error);
3443 return_val_if_nok (error, NULL);
3444 v = ((gchar *) o) + sizeof (MonoObject);
3447 get_default_field_value (domain, field, v, error);
3448 return_val_if_nok (error, NULL);
3449 } else if (is_static) {
3450 mono_field_static_get_value_checked (vtable, field, v, error);
3451 return_val_if_nok (error, NULL);
3453 mono_field_get_value (obj, field, v);
3460 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3462 MONO_REQ_GC_UNSAFE_MODE;
3466 const char *p = blob;
3467 mono_metadata_decode_blob_size (p, &p);
3470 case MONO_TYPE_BOOLEAN:
3473 *(guint8 *) value = *p;
3475 case MONO_TYPE_CHAR:
3478 *(guint16*) value = read16 (p);
3482 *(guint32*) value = read32 (p);
3486 *(guint64*) value = read64 (p);
3489 readr4 (p, (float*) value);
3492 readr8 (p, (double*) value);
3494 case MONO_TYPE_STRING:
3495 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3497 case MONO_TYPE_CLASS:
3498 *(gpointer*) value = NULL;
3502 g_warning ("type 0x%02x should not be in constant table", type);
3508 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3510 MONO_REQ_GC_NEUTRAL_MODE;
3512 MonoTypeEnum def_type;
3517 data = mono_class_get_field_default_value (field, &def_type);
3518 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3522 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3524 MONO_REQ_GC_UNSAFE_MODE;
3530 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3532 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3533 get_default_field_value (vt->domain, field, value, error);
3537 if (field->offset == -1) {
3538 /* Special static */
3539 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3540 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3542 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3544 mono_copy_value (field->type, value, src, TRUE);
3548 * mono_field_static_get_value:
3549 * \param vt vtable to the object
3550 * \param field \c MonoClassField describing the field to fetch information from
3551 * \param value where the value is returned
3552 * Use this routine to get the value of the static field \p field value.
3554 * The pointer provided by value must be of the field type, for reference
3555 * types this is a \c MonoObject*, for value types its the actual pointer to
3560 * mono_field_static_get_value (vt, int_field, &i);
3563 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3565 MONO_REQ_GC_NEUTRAL_MODE;
3568 mono_field_static_get_value_checked (vt, field, value, &error);
3569 mono_error_cleanup (&error);
3573 * mono_field_static_get_value_checked:
3574 * \param vt vtable to the object
3575 * \param field \c MonoClassField describing the field to fetch information from
3576 * \param value where the value is returned
3577 * \param error set on error
3578 * Use this routine to get the value of the static field \p field value.
3580 * The pointer provided by value must be of the field type, for reference
3581 * types this is a \c MonoObject*, for value types its the actual pointer to
3586 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3587 * if (!is_ok (error)) { ... }
3589 * On failure sets \p error.
3592 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3594 MONO_REQ_GC_NEUTRAL_MODE;
3596 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3600 * mono_property_set_value:
3601 * \param prop MonoProperty to set
3602 * \param obj instance object on which to act
3603 * \param params parameters to pass to the propery
3604 * \param exc optional exception
3605 * Invokes the property's set method with the given arguments on the
3606 * object instance obj (or NULL for static properties).
3608 * You can pass NULL as the exc argument if you don't want to
3609 * catch exceptions, otherwise, \c *exc will be set to the exception
3610 * thrown, if any. if an exception is thrown, you can't use the
3611 * \c MonoObject* result from the function.
3614 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3616 MONO_REQ_GC_UNSAFE_MODE;
3619 do_runtime_invoke (prop->set, obj, params, exc, &error);
3620 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3621 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3623 mono_error_cleanup (&error);
3628 * mono_property_set_value_checked:
3629 * \param prop \c MonoProperty to set
3630 * \param obj instance object on which to act
3631 * \param params parameters to pass to the propery
3632 * \param error set on error
3633 * Invokes the property's set method with the given arguments on the
3634 * object instance \p obj (or NULL for static properties).
3635 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3636 * If an exception is thrown, it will be caught and returned via \p error.
3639 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3641 MONO_REQ_GC_UNSAFE_MODE;
3646 do_runtime_invoke (prop->set, obj, params, &exc, error);
3647 if (exc != NULL && is_ok (error))
3648 mono_error_set_exception_instance (error, (MonoException*)exc);
3649 return is_ok (error);
3653 * mono_property_get_value:
3654 * \param prop \c MonoProperty to fetch
3655 * \param obj instance object on which to act
3656 * \param params parameters to pass to the propery
3657 * \param exc optional exception
3658 * Invokes the property's \c get method with the given arguments on the
3659 * object instance \p obj (or NULL for static properties).
3661 * You can pass NULL as the \p exc argument if you don't want to
3662 * catch exceptions, otherwise, \c *exc will be set to the exception
3663 * thrown, if any. if an exception is thrown, you can't use the
3664 * \c MonoObject* result from the function.
3666 * \returns the value from invoking the \c get method on the property.
3669 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3671 MONO_REQ_GC_UNSAFE_MODE;
3674 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3675 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3676 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3678 mono_error_cleanup (&error); /* FIXME don't raise here */
3685 * mono_property_get_value_checked:
3686 * \param prop \c MonoProperty to fetch
3687 * \param obj instance object on which to act
3688 * \param params parameters to pass to the propery
3689 * \param error set on error
3690 * Invokes the property's \c get method with the given arguments on the
3691 * object instance obj (or NULL for static properties).
3693 * If an exception is thrown, you can't use the
3694 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3696 * \returns the value from invoking the get method on the property. On
3697 * failure returns NULL and sets \p error.
3700 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3702 MONO_REQ_GC_UNSAFE_MODE;
3705 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3706 if (exc != NULL && !is_ok (error))
3707 mono_error_set_exception_instance (error, (MonoException*) exc);
3715 * mono_nullable_init:
3716 * @buf: The nullable structure to initialize.
3717 * @value: the value to initialize from
3718 * @klass: the type for the object
3720 * Initialize the nullable structure pointed to by @buf from @value which
3721 * should be a boxed value type. The size of @buf should be able to hold
3722 * as much data as the @klass->instance_size (which is the number of bytes
3723 * that will be copies).
3725 * Since Nullables have variable structure, we can not define a C
3726 * structure for them.
3729 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3731 MONO_REQ_GC_UNSAFE_MODE;
3733 MonoClass *param_class = klass->cast_class;
3735 mono_class_setup_fields (klass);
3736 g_assert (klass->fields_inited);
3738 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3739 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3741 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3743 if (param_class->has_references)
3744 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3746 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3748 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3753 * mono_nullable_box:
3754 * \param buf The buffer representing the data to be boxed
3755 * \param klass the type to box it as.
3756 * \param error set on error
3758 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3759 * \p buf. On failure returns NULL and sets \p error.
3762 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3764 MONO_REQ_GC_UNSAFE_MODE;
3767 MonoClass *param_class = klass->cast_class;
3769 mono_class_setup_fields (klass);
3770 g_assert (klass->fields_inited);
3772 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3773 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3775 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3776 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3777 return_val_if_nok (error, NULL);
3778 if (param_class->has_references)
3779 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3781 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3789 * mono_get_delegate_invoke:
3790 * \param klass The delegate class
3791 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3794 mono_get_delegate_invoke (MonoClass *klass)
3796 MONO_REQ_GC_NEUTRAL_MODE;
3800 /* This is called at runtime, so avoid the slower search in metadata */
3801 mono_class_setup_methods (klass);
3802 if (mono_class_has_failure (klass))
3804 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3809 * mono_get_delegate_begin_invoke:
3810 * \param klass The delegate class
3811 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3814 mono_get_delegate_begin_invoke (MonoClass *klass)
3816 MONO_REQ_GC_NEUTRAL_MODE;
3820 /* This is called at runtime, so avoid the slower search in metadata */
3821 mono_class_setup_methods (klass);
3822 if (mono_class_has_failure (klass))
3824 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3829 * mono_get_delegate_end_invoke:
3830 * \param klass The delegate class
3831 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3834 mono_get_delegate_end_invoke (MonoClass *klass)
3836 MONO_REQ_GC_NEUTRAL_MODE;
3840 /* This is called at runtime, so avoid the slower search in metadata */
3841 mono_class_setup_methods (klass);
3842 if (mono_class_has_failure (klass))
3844 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3849 * mono_runtime_delegate_invoke:
3850 * \param delegate pointer to a delegate object.
3851 * \param params parameters for the delegate.
3852 * \param exc Pointer to the exception result.
3854 * Invokes the delegate method \p delegate with the parameters provided.
3856 * You can pass NULL as the \p exc argument if you don't want to
3857 * catch exceptions, otherwise, \c *exc will be set to the exception
3858 * thrown, if any. if an exception is thrown, you can't use the
3859 * \c MonoObject* result from the function.
3862 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3864 MONO_REQ_GC_UNSAFE_MODE;
3868 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3870 mono_error_cleanup (&error);
3873 if (!is_ok (&error))
3874 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3878 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3879 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3885 * mono_runtime_delegate_try_invoke:
3886 * \param delegate pointer to a delegate object.
3887 * \param params parameters for the delegate.
3888 * \param exc Pointer to the exception result.
3889 * \param error set on error
3890 * Invokes the delegate method \p delegate with the parameters provided.
3892 * You can pass NULL as the \p exc argument if you don't want to
3893 * catch exceptions, otherwise, \c *exc will be set to the exception
3894 * thrown, if any. On failure to execute, \p error will be set.
3895 * if an exception is thrown, you can't use the
3896 * \c MonoObject* result from the function.
3899 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3901 MONO_REQ_GC_UNSAFE_MODE;
3905 MonoClass *klass = delegate->vtable->klass;
3908 im = mono_get_delegate_invoke (klass);
3910 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3913 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3915 o = mono_runtime_invoke_checked (im, delegate, params, error);
3922 * mono_runtime_delegate_invoke_checked:
3923 * \param delegate pointer to a delegate object.
3924 * \param params parameters for the delegate.
3925 * \param error set on error
3926 * Invokes the delegate method \p delegate with the parameters provided.
3927 * On failure \p error will be set and you can't use the \c MonoObject*
3928 * result from the function.
3931 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3934 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3937 static char **main_args = NULL;
3938 static int num_main_args = 0;
3941 * mono_runtime_get_main_args:
3943 * Returns: a MonoArray with the arguments passed to the main program
3946 mono_runtime_get_main_args (void)
3948 MONO_REQ_GC_UNSAFE_MODE;
3950 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3951 mono_error_assert_ok (&error);
3956 * mono_runtime_get_main_args_checked:
3957 * \param error set on error
3958 * \returns a \c MonoArray with the arguments passed to the main
3959 * program. On failure returns NULL and sets \p error.
3962 mono_runtime_get_main_args_checked (MonoError *error)
3966 MonoDomain *domain = mono_domain_get ();
3970 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3971 return_val_if_nok (error, NULL);
3973 for (i = 0; i < num_main_args; ++i)
3974 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3980 free_main_args (void)
3982 MONO_REQ_GC_NEUTRAL_MODE;
3986 for (i = 0; i < num_main_args; ++i)
3987 g_free (main_args [i]);
3994 * mono_runtime_set_main_args:
3995 * \param argc number of arguments from the command line
3996 * \param argv array of strings from the command line
3997 * Set the command line arguments from an embedding application that doesn't otherwise call
3998 * \c mono_runtime_run_main.
4001 mono_runtime_set_main_args (int argc, char* argv[])
4003 MONO_REQ_GC_NEUTRAL_MODE;
4008 main_args = g_new0 (char*, argc);
4009 num_main_args = argc;
4011 for (i = 0; i < argc; ++i) {
4014 utf8_arg = mono_utf8_from_external (argv[i]);
4015 if (utf8_arg == NULL) {
4016 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4017 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4021 main_args [i] = utf8_arg;
4028 * Prepare an array of arguments in order to execute a standard Main()
4029 * method (argc/argv contains the executable name). This method also
4030 * sets the command line argument value needed by System.Environment.
4034 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4036 MONO_REQ_GC_UNSAFE_MODE;
4040 MonoArray *args = NULL;
4041 MonoDomain *domain = mono_domain_get ();
4042 gchar *utf8_fullpath;
4043 MonoMethodSignature *sig;
4045 g_assert (method != NULL);
4047 mono_thread_set_main (mono_thread_current ());
4049 main_args = g_new0 (char*, argc);
4050 num_main_args = argc;
4052 if (!g_path_is_absolute (argv [0])) {
4053 gchar *basename = g_path_get_basename (argv [0]);
4054 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4058 utf8_fullpath = mono_utf8_from_external (fullpath);
4059 if(utf8_fullpath == NULL) {
4060 /* Printing the arg text will cause glib to
4061 * whinge about "Invalid UTF-8", but at least
4062 * its relevant, and shows the problem text
4065 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4066 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4073 utf8_fullpath = mono_utf8_from_external (argv[0]);
4074 if(utf8_fullpath == NULL) {
4075 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4076 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4081 main_args [0] = utf8_fullpath;
4083 for (i = 1; i < argc; ++i) {
4086 utf8_arg=mono_utf8_from_external (argv[i]);
4087 if(utf8_arg==NULL) {
4088 /* Ditto the comment about Invalid UTF-8 here */
4089 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4090 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4094 main_args [i] = utf8_arg;
4099 sig = mono_method_signature (method);
4101 g_print ("Unable to load Main method.\n");
4105 if (sig->param_count) {
4106 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4107 mono_error_assert_ok (&error);
4108 for (i = 0; i < argc; ++i) {
4109 /* The encodings should all work, given that
4110 * we've checked all these args for the
4113 gchar *str = mono_utf8_from_external (argv [i]);
4114 MonoString *arg = mono_string_new (domain, str);
4115 mono_array_setref (args, i, arg);
4119 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4120 mono_error_assert_ok (&error);
4123 mono_assembly_set_main (method->klass->image->assembly);
4129 * mono_runtime_run_main:
4130 * \param method the method to start the application with (usually \c Main)
4131 * \param argc number of arguments from the command line
4132 * \param argv array of strings from the command line
4133 * \param exc excetption results
4134 * Execute a standard \c Main method (\p argc / \p argv contains the
4135 * executable name). This method also sets the command line argument value
4136 * needed by \c System.Environment.
4139 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4142 MONO_REQ_GC_UNSAFE_MODE;
4145 MonoArray *args = prepare_run_main (method, argc, argv);
4148 res = mono_runtime_try_exec_main (method, args, exc);
4150 res = mono_runtime_exec_main_checked (method, args, &error);
4151 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4157 * mono_runtime_run_main_checked:
4158 * \param method the method to start the application with (usually \c Main)
4159 * \param argc number of arguments from the command line
4160 * \param argv array of strings from the command line
4161 * \param error set on error
4163 * Execute a standard \c Main method (\p argc / \p argv contains the
4164 * executable name). This method also sets the command line argument value
4165 * needed by \c System.Environment. On failure sets \p error.
4168 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4172 MonoArray *args = prepare_run_main (method, argc, argv);
4173 return mono_runtime_exec_main_checked (method, args, error);
4177 * mono_runtime_try_run_main:
4178 * \param method the method to start the application with (usually \c Main)
4179 * \param argc number of arguments from the command line
4180 * \param argv array of strings from the command line
4181 * \param exc set if \c Main throws an exception
4182 * \param error set if \c Main can't be executed
4183 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4184 * name). This method also sets the command line argument value needed
4185 * by \c System.Environment. On failure sets \p error if Main can't be
4186 * executed or \p exc if it threw an exception.
4189 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4193 MonoArray *args = prepare_run_main (method, argc, argv);
4194 return mono_runtime_try_exec_main (method, args, exc);
4199 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4201 static MonoMethod *serialize_method;
4207 if (!serialize_method) {
4208 MonoClass *klass = mono_class_get_remoting_services_class ();
4209 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4212 if (!serialize_method) {
4217 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4222 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4223 if (*exc == NULL && !mono_error_ok (&error))
4224 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4226 mono_error_cleanup (&error);
4235 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4237 MONO_REQ_GC_UNSAFE_MODE;
4239 static MonoMethod *deserialize_method;
4245 if (!deserialize_method) {
4246 MonoClass *klass = mono_class_get_remoting_services_class ();
4247 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4249 if (!deserialize_method) {
4257 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4258 if (*exc == NULL && !mono_error_ok (&error))
4259 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4261 mono_error_cleanup (&error);
4269 #ifndef DISABLE_REMOTING
4271 make_transparent_proxy (MonoObject *obj, MonoError *error)
4273 MONO_REQ_GC_UNSAFE_MODE;
4275 static MonoMethod *get_proxy_method;
4277 MonoDomain *domain = mono_domain_get ();
4278 MonoRealProxy *real_proxy;
4279 MonoReflectionType *reflection_type;
4280 MonoTransparentProxy *transparent_proxy;
4284 if (!get_proxy_method)
4285 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4287 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4289 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4290 return_val_if_nok (error, NULL);
4291 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4292 return_val_if_nok (error, NULL);
4294 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4295 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4297 MonoObject *exc = NULL;
4299 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4300 if (exc != NULL && is_ok (error))
4301 mono_error_set_exception_instance (error, (MonoException*)exc);
4303 return (MonoObject*) transparent_proxy;
4305 #endif /* DISABLE_REMOTING */
4308 * mono_object_xdomain_representation
4309 * \param obj an object
4310 * \param target_domain a domain
4311 * \param error set on error.
4312 * Creates a representation of obj in the domain \p target_domain. This
4313 * is either a copy of \p obj arrived through via serialization and
4314 * deserialization or a proxy, depending on whether the object is
4315 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4316 * If the object cannot be represented in \p target_domain, NULL is
4317 * returned and \p error is set appropriately.
4320 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4322 MONO_REQ_GC_UNSAFE_MODE;
4325 MonoObject *deserialized = NULL;
4327 #ifndef DISABLE_REMOTING
4328 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4329 deserialized = make_transparent_proxy (obj, error);
4334 gboolean failure = FALSE;
4335 MonoDomain *domain = mono_domain_get ();
4336 MonoObject *serialized;
4337 MonoObject *exc = NULL;
4339 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4340 serialized = serialize_object (obj, &failure, &exc);
4341 mono_domain_set_internal_with_options (target_domain, FALSE);
4343 deserialized = deserialize_object (serialized, &failure, &exc);
4344 if (domain != target_domain)
4345 mono_domain_set_internal_with_options (domain, FALSE);
4347 mono_error_set_exception_instance (error, (MonoException*)exc);
4350 return deserialized;
4353 /* Used in call_unhandled_exception_delegate */
4355 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4357 MONO_REQ_GC_UNSAFE_MODE;
4362 MonoMethod *method = NULL;
4363 MonoBoolean is_terminating = TRUE;
4366 klass = mono_class_get_unhandled_exception_event_args_class ();
4367 mono_class_init (klass);
4369 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4370 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4374 args [1] = &is_terminating;
4376 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4377 return_val_if_nok (error, NULL);
4379 mono_runtime_invoke_checked (method, obj, args, error);
4380 return_val_if_nok (error, NULL);
4385 /* Used in mono_unhandled_exception */
4387 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4388 MONO_REQ_GC_UNSAFE_MODE;
4391 MonoObject *e = NULL;
4393 MonoDomain *current_domain = mono_domain_get ();
4395 if (domain != current_domain)
4396 mono_domain_set_internal_with_options (domain, FALSE);
4398 g_assert (domain == mono_object_domain (domain->domain));
4400 if (mono_object_domain (exc) != domain) {
4402 exc = mono_object_xdomain_representation (exc, domain, &error);
4404 if (!is_ok (&error)) {
4405 MonoError inner_error;
4406 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4407 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4408 mono_error_assert_ok (&inner_error);
4410 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4411 "System.Runtime.Serialization", "SerializationException",
4412 "Could not serialize unhandled exception.");
4416 g_assert (mono_object_domain (exc) == domain);
4418 pa [0] = domain->domain;
4419 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4420 mono_error_assert_ok (&error);
4421 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4422 if (!is_ok (&error)) {
4424 e = (MonoObject*)mono_error_convert_to_exception (&error);
4426 mono_error_cleanup (&error);
4429 if (domain != current_domain)
4430 mono_domain_set_internal_with_options (current_domain, FALSE);
4433 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4434 if (!mono_error_ok (&error)) {
4435 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4436 mono_error_cleanup (&error);
4438 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4444 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4447 * mono_runtime_unhandled_exception_policy_set:
4448 * \param policy the new policy
4449 * This is a VM internal routine.
4450 * Sets the runtime policy for handling unhandled exceptions.
4453 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4454 runtime_unhandled_exception_policy = policy;
4458 * mono_runtime_unhandled_exception_policy_get:
4460 * This is a VM internal routine.
4462 * Gets the runtime policy for handling unhandled exceptions.
4464 MonoRuntimeUnhandledExceptionPolicy
4465 mono_runtime_unhandled_exception_policy_get (void) {
4466 return runtime_unhandled_exception_policy;
4470 * mono_unhandled_exception:
4471 * \param exc exception thrown
4472 * This is a VM internal routine.
4474 * We call this function when we detect an unhandled exception
4475 * in the default domain.
4477 * It invokes the \c UnhandledException event in \c AppDomain or prints
4478 * a warning to the console
4481 mono_unhandled_exception (MonoObject *exc)
4483 MONO_REQ_GC_UNSAFE_MODE;
4486 MonoClassField *field;
4487 MonoDomain *current_domain, *root_domain;
4488 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4490 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4493 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4496 current_domain = mono_domain_get ();
4497 root_domain = mono_get_root_domain ();
4499 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4500 mono_error_assert_ok (&error);
4501 if (current_domain != root_domain) {
4502 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4503 mono_error_assert_ok (&error);
4506 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4507 mono_print_unhandled_exception (exc);
4509 /* unhandled exception callbacks must not be aborted */
4510 mono_threads_begin_abort_protected_block ();
4511 if (root_appdomain_delegate)
4512 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4513 if (current_appdomain_delegate)
4514 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4515 mono_threads_end_abort_protected_block ();
4518 /* set exitcode only if we will abort the process */
4519 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4520 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4522 mono_environment_exitcode_set (1);
4527 * mono_runtime_exec_managed_code:
4528 * \param domain Application domain
4529 * \param main_func function to invoke from the execution thread
4530 * \param main_args parameter to the main_func
4531 * Launch a new thread to execute a function
4533 * \p main_func is called back from the thread with main_args as the
4534 * parameter. The callback function is expected to start \c Main
4535 * eventually. This function then waits for all managed threads to
4537 * It is not necessary anymore to execute managed code in a subthread,
4538 * so this function should not be used anymore by default: just
4539 * execute the code and then call mono_thread_manage().
4542 mono_runtime_exec_managed_code (MonoDomain *domain,
4543 MonoMainThreadFunc main_func,
4547 mono_thread_create_checked (domain, main_func, main_args, &error);
4548 mono_error_assert_ok (&error);
4550 mono_thread_manage ();
4554 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4556 MonoInternalThread* thread = mono_thread_internal_current ();
4557 MonoCustomAttrInfo* cinfo;
4558 gboolean has_stathread_attribute;
4560 if (!domain->entry_assembly) {
4562 MonoAssembly *assembly;
4564 assembly = method->klass->image->assembly;
4565 domain->entry_assembly = assembly;
4566 /* Domains created from another domain already have application_base and configuration_file set */
4567 if (domain->setup->application_base == NULL) {
4568 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4571 if (domain->setup->configuration_file == NULL) {
4572 str = g_strconcat (assembly->image->name, ".config", NULL);
4573 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4575 mono_domain_set_options_from_config (domain);
4579 MonoError cattr_error;
4580 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4581 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4583 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4585 mono_custom_attrs_free (cinfo);
4587 has_stathread_attribute = FALSE;
4589 if (has_stathread_attribute) {
4590 thread->apartment_state = ThreadApartmentState_STA;
4592 thread->apartment_state = ThreadApartmentState_MTA;
4594 mono_thread_init_apartment_state ();
4599 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4601 MONO_REQ_GC_UNSAFE_MODE;
4611 /* FIXME: check signature of method */
4612 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4614 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4616 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4619 mono_environment_exitcode_set (rval);
4621 mono_runtime_invoke_checked (method, NULL, pa, error);
4633 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4635 MONO_REQ_GC_UNSAFE_MODE;
4645 /* FIXME: check signature of method */
4646 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4647 MonoError inner_error;
4649 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4650 if (*exc == NULL && !mono_error_ok (&inner_error))
4651 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4653 mono_error_cleanup (&inner_error);
4656 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4660 mono_environment_exitcode_set (rval);
4662 MonoError inner_error;
4663 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4664 if (*exc == NULL && !mono_error_ok (&inner_error))
4665 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4667 mono_error_cleanup (&inner_error);
4672 /* If the return type of Main is void, only
4673 * set the exitcode if an exception was thrown
4674 * (we don't want to blow away an
4675 * explicitly-set exit code)
4678 mono_environment_exitcode_set (rval);
4686 * Execute a standard Main() method (args doesn't contain the
4690 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4693 prepare_thread_to_exec_main (mono_object_domain (args), method);
4695 int rval = do_try_exec_main (method, args, exc);
4698 int rval = do_exec_main_checked (method, args, &error);
4699 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4705 * Execute a standard Main() method (args doesn't contain the
4708 * On failure sets @error
4711 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4714 prepare_thread_to_exec_main (mono_object_domain (args), method);
4715 return do_exec_main_checked (method, args, error);
4719 * Execute a standard Main() method (args doesn't contain the
4722 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4725 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4727 prepare_thread_to_exec_main (mono_object_domain (args), method);
4728 return do_try_exec_main (method, args, exc);
4733 /** invoke_array_extract_argument:
4734 * @params: array of arguments to the method.
4735 * @i: the index of the argument to extract.
4736 * @t: ith type from the method signature.
4737 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4738 * @error: set on error.
4740 * Given an array of method arguments, return the ith one using the corresponding type
4741 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4743 * On failure sets @error and returns NULL.
4746 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4748 MonoType *t_orig = t;
4749 gpointer result = NULL;
4755 case MONO_TYPE_BOOLEAN:
4758 case MONO_TYPE_CHAR:
4767 case MONO_TYPE_VALUETYPE:
4768 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4769 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4770 result = mono_array_get (params, MonoObject*, i);
4772 *has_byref_nullables = TRUE;
4774 /* MS seems to create the objects if a null is passed in */
4775 gboolean was_null = FALSE;
4776 if (!mono_array_get (params, MonoObject*, i)) {
4777 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4778 return_val_if_nok (error, NULL);
4779 mono_array_setref (params, i, o);
4785 * We can't pass the unboxed vtype byref to the callee, since
4786 * that would mean the callee would be able to modify boxed
4787 * primitive types. So we (and MS) make a copy of the boxed
4788 * object, pass that to the callee, and replace the original
4789 * boxed object in the arg array with the copy.
4791 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4792 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4793 return_val_if_nok (error, NULL);
4794 mono_array_setref (params, i, copy);
4797 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4798 if (!t->byref && was_null)
4799 mono_array_setref (params, i, NULL);
4802 case MONO_TYPE_STRING:
4803 case MONO_TYPE_OBJECT:
4804 case MONO_TYPE_CLASS:
4805 case MONO_TYPE_ARRAY:
4806 case MONO_TYPE_SZARRAY:
4808 result = mono_array_addr (params, MonoObject*, i);
4809 // FIXME: I need to check this code path
4811 result = mono_array_get (params, MonoObject*, i);
4813 case MONO_TYPE_GENERICINST:
4815 t = &t->data.generic_class->container_class->this_arg;
4817 t = &t->data.generic_class->container_class->byval_arg;
4819 case MONO_TYPE_PTR: {
4822 /* The argument should be an IntPtr */
4823 arg = mono_array_get (params, MonoObject*, i);
4827 g_assert (arg->vtable->klass == mono_defaults.int_class);
4828 result = ((MonoIntPtr*)arg)->m_value;
4833 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4838 * mono_runtime_invoke_array:
4839 * \param method method to invoke
4840 * \param obj object instance
4841 * \param params arguments to the method
4842 * \param exc exception information.
4843 * Invokes the method represented by \p method on the object \p obj.
4845 * \p obj is the \c this pointer, it should be NULL for static
4846 * methods, a \c MonoObject* for object instances and a pointer to
4847 * the value type for value types.
4849 * The \p params array contains the arguments to the method with the
4850 * same convention: \c MonoObject* pointers for object instances and
4851 * pointers to the value type otherwise. The \c _invoke_array
4852 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4853 * in this case the value types are boxed inside the
4854 * respective reference representation.
4856 * From unmanaged code you'll usually use the
4857 * mono_runtime_invoke_checked() variant.
4859 * Note that this function doesn't handle virtual methods for
4860 * you, it will exec the exact method you pass: we still need to
4861 * expose a function to lookup the derived class implementation
4862 * of a virtual method (there are examples of this in the code,
4865 * You can pass NULL as the \p exc argument if you don't want to
4866 * catch exceptions, otherwise, \c *exc will be set to the exception
4867 * thrown, if any. if an exception is thrown, you can't use the
4868 * \c MonoObject* result from the function.
4870 * If the method returns a value type, it is boxed in an object
4874 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4879 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4881 mono_error_cleanup (&error);
4884 if (!is_ok (&error))
4885 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4889 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4890 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4896 * mono_runtime_invoke_array_checked:
4897 * \param method method to invoke
4898 * \param obj object instance
4899 * \param params arguments to the method
4900 * \param error set on failure.
4901 * Invokes the method represented by \p method on the object \p obj.
4903 * \p obj is the \c this pointer, it should be NULL for static
4904 * methods, a \c MonoObject* for object instances and a pointer to
4905 * the value type for value types.
4907 * The \p params array contains the arguments to the method with the
4908 * same convention: \c MonoObject* pointers for object instances and
4909 * pointers to the value type otherwise. The \c _invoke_array
4910 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4911 * in this case the value types are boxed inside the
4912 * respective reference representation.
4914 * From unmanaged code you'll usually use the
4915 * mono_runtime_invoke_checked() variant.
4917 * Note that this function doesn't handle virtual methods for
4918 * you, it will exec the exact method you pass: we still need to
4919 * expose a function to lookup the derived class implementation
4920 * of a virtual method (there are examples of this in the code,
4923 * On failure or exception, \p error will be set. In that case, you
4924 * can't use the \c MonoObject* result from the function.
4926 * If the method returns a value type, it is boxed in an object
4930 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4934 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4938 * mono_runtime_try_invoke_array:
4939 * \param method method to invoke
4940 * \param obj object instance
4941 * \param params arguments to the method
4942 * \param exc exception information.
4943 * \param error set on failure.
4944 * Invokes the method represented by \p method on the object \p obj.
4946 * \p obj is the \c this pointer, it should be NULL for static
4947 * methods, a \c MonoObject* for object instances and a pointer to
4948 * the value type for value types.
4950 * The \p params array contains the arguments to the method with the
4951 * same convention: \c MonoObject* pointers for object instances and
4952 * pointers to the value type otherwise. The \c _invoke_array
4953 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4954 * in this case the value types are boxed inside the
4955 * respective reference representation.
4957 * From unmanaged code you'll usually use the
4958 * mono_runtime_invoke_checked() variant.
4960 * Note that this function doesn't handle virtual methods for
4961 * you, it will exec the exact method you pass: we still need to
4962 * expose a function to lookup the derived class implementation
4963 * of a virtual method (there are examples of this in the code,
4966 * You can pass NULL as the \p exc argument if you don't want to catch
4967 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
4968 * any. On other failures, \p error will be set. If an exception is
4969 * thrown or there's an error, you can't use the \c MonoObject* result
4970 * from the function.
4972 * If the method returns a value type, it is boxed in an object
4976 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4977 MonoObject **exc, MonoError *error)
4979 MONO_REQ_GC_UNSAFE_MODE;
4983 MonoMethodSignature *sig = mono_method_signature (method);
4984 gpointer *pa = NULL;
4987 gboolean has_byref_nullables = FALSE;
4989 if (NULL != params) {
4990 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4991 for (i = 0; i < mono_array_length (params); i++) {
4992 MonoType *t = sig->params [i];
4993 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4994 return_val_if_nok (error, NULL);
4998 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5001 if (mono_class_is_nullable (method->klass)) {
5002 /* Need to create a boxed vtype instead */
5008 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5013 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5014 mono_error_assert_ok (error);
5015 g_assert (obj); /*maybe we should raise a TLE instead?*/
5016 #ifndef DISABLE_REMOTING
5017 if (mono_object_is_transparent_proxy (obj)) {
5018 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5021 if (method->klass->valuetype)
5022 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5025 } else if (method->klass->valuetype) {
5026 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5027 return_val_if_nok (error, NULL);
5031 mono_runtime_try_invoke (method, o, pa, exc, error);
5033 mono_runtime_invoke_checked (method, o, pa, error);
5036 return (MonoObject *)obj;
5038 if (mono_class_is_nullable (method->klass)) {
5039 MonoObject *nullable;
5041 /* Convert the unboxed vtype into a Nullable structure */
5042 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5043 return_val_if_nok (error, NULL);
5045 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5046 return_val_if_nok (error, NULL);
5047 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5048 obj = mono_object_unbox (nullable);
5051 /* obj must be already unboxed if needed */
5053 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5055 res = mono_runtime_invoke_checked (method, obj, pa, error);
5057 return_val_if_nok (error, NULL);
5059 if (sig->ret->type == MONO_TYPE_PTR) {
5060 MonoClass *pointer_class;
5061 static MonoMethod *box_method;
5063 MonoObject *box_exc;
5066 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5067 * convert it to a Pointer object.
5069 pointer_class = mono_class_get_pointer_class ();
5071 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5073 g_assert (res->vtable->klass == mono_defaults.int_class);
5074 box_args [0] = ((MonoIntPtr*)res)->m_value;
5075 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5076 return_val_if_nok (error, NULL);
5078 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5079 g_assert (box_exc == NULL);
5080 mono_error_assert_ok (error);
5083 if (has_byref_nullables) {
5085 * The runtime invoke wrapper already converted byref nullables back,
5086 * and stored them in pa, we just need to copy them back to the
5089 for (i = 0; i < mono_array_length (params); i++) {
5090 MonoType *t = sig->params [i];
5092 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5093 mono_array_setref (params, i, pa [i]);
5103 * \param klass the class of the object that we want to create
5104 * \returns a newly created object whose definition is
5105 * looked up using \p klass. This will not invoke any constructors,
5106 * so the consumer of this routine has to invoke any constructors on
5107 * its own to initialize the object.
5109 * It returns NULL on failure.
5112 mono_object_new (MonoDomain *domain, MonoClass *klass)
5114 MONO_REQ_GC_UNSAFE_MODE;
5118 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5120 mono_error_cleanup (&error);
5125 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5127 MONO_REQ_GC_UNSAFE_MODE;
5131 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5133 mono_error_set_pending_exception (&error);
5138 * mono_object_new_checked:
5139 * \param klass the class of the object that we want to create
5140 * \param error set on error
5141 * \returns a newly created object whose definition is
5142 * looked up using \p klass. This will not invoke any constructors,
5143 * so the consumer of this routine has to invoke any constructors on
5144 * its own to initialize the object.
5146 * It returns NULL on failure and sets \p error.
5149 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5151 MONO_REQ_GC_UNSAFE_MODE;
5155 vtable = mono_class_vtable (domain, klass);
5156 g_assert (vtable); /* FIXME don't swallow the error */
5158 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5163 * mono_object_new_pinned:
5165 * Same as mono_object_new, but the returned object will be pinned.
5166 * For SGEN, these objects will only be freed at appdomain unload.
5169 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5171 MONO_REQ_GC_UNSAFE_MODE;
5177 vtable = mono_class_vtable (domain, klass);
5178 g_assert (vtable); /* FIXME don't swallow the error */
5180 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5182 if (G_UNLIKELY (!o))
5183 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5184 else if (G_UNLIKELY (vtable->klass->has_finalize))
5185 mono_object_register_finalizer (o);
5191 * mono_object_new_specific:
5192 * \param vtable the vtable of the object that we want to create
5193 * \returns A newly created object with class and domain specified
5197 mono_object_new_specific (MonoVTable *vtable)
5200 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5201 mono_error_cleanup (&error);
5207 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5209 MONO_REQ_GC_UNSAFE_MODE;
5215 /* check for is_com_object for COM Interop */
5216 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5219 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5222 MonoClass *klass = mono_class_get_activation_services_class ();
5225 mono_class_init (klass);
5227 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5229 mono_error_set_not_supported (error, "Linked away.");
5232 vtable->domain->create_proxy_for_type_method = im;
5235 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5236 if (!mono_error_ok (error))
5239 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5240 if (!mono_error_ok (error))
5247 return mono_object_new_alloc_specific_checked (vtable, error);
5251 ves_icall_object_new_specific (MonoVTable *vtable)
5254 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5255 mono_error_set_pending_exception (&error);
5261 * mono_object_new_alloc_specific:
5262 * \param vtable virtual table for the object.
5263 * This function allocates a new \c MonoObject with the type derived
5264 * from the \p vtable information. If the class of this object has a
5265 * finalizer, then the object will be tracked for finalization.
5267 * This method might raise an exception on errors. Use the
5268 * \c mono_object_new_fast_checked method if you want to manually raise
5271 * \returns the allocated object.
5274 mono_object_new_alloc_specific (MonoVTable *vtable)
5277 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5278 mono_error_cleanup (&error);
5284 * mono_object_new_alloc_specific_checked:
5285 * \param vtable virtual table for the object.
5286 * \param error holds the error return value.
5288 * This function allocates a new \c MonoObject with the type derived
5289 * from the \p vtable information. If the class of this object has a
5290 * finalizer, then the object will be tracked for finalization.
5292 * If there is not enough memory, the \p error parameter will be set
5293 * and will contain a user-visible message with the amount of bytes
5294 * that were requested.
5296 * \returns the allocated object, or NULL if there is not enough memory
5299 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5301 MONO_REQ_GC_UNSAFE_MODE;
5307 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5309 if (G_UNLIKELY (!o))
5310 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5311 else if (G_UNLIKELY (vtable->klass->has_finalize))
5312 mono_object_register_finalizer (o);
5318 * mono_object_new_fast:
5319 * \param vtable virtual table for the object.
5321 * This function allocates a new \c MonoObject with the type derived
5322 * from the \p vtable information. The returned object is not tracked
5323 * for finalization. If your object implements a finalizer, you should
5324 * use \c mono_object_new_alloc_specific instead.
5326 * This method might raise an exception on errors. Use the
5327 * \c mono_object_new_fast_checked method if you want to manually raise
5330 * \returns the allocated object.
5333 mono_object_new_fast (MonoVTable *vtable)
5336 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5337 mono_error_cleanup (&error);
5343 * mono_object_new_fast_checked:
5344 * \param vtable virtual table for the object.
5345 * \param error holds the error return value.
5347 * This function allocates a new \c MonoObject with the type derived
5348 * from the \p vtable information. The returned object is not tracked
5349 * for finalization. If your object implements a finalizer, you should
5350 * use \c mono_object_new_alloc_specific_checked instead.
5352 * If there is not enough memory, the \p error parameter will be set
5353 * and will contain a user-visible message with the amount of bytes
5354 * that were requested.
5356 * \returns the allocated object, or NULL if there is not enough memory
5359 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5361 MONO_REQ_GC_UNSAFE_MODE;
5367 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5369 if (G_UNLIKELY (!o))
5370 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5376 ves_icall_object_new_fast (MonoVTable *vtable)
5379 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5380 mono_error_set_pending_exception (&error);
5386 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5388 MONO_REQ_GC_UNSAFE_MODE;
5394 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5396 if (G_UNLIKELY (!o))
5397 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5398 else if (G_UNLIKELY (vtable->klass->has_finalize))
5399 mono_object_register_finalizer (o);
5405 * mono_class_get_allocation_ftn:
5406 * \param vtable vtable
5407 * \param for_box the object will be used for boxing
5408 * \param pass_size_in_words Unused
5409 * \returns the allocation function appropriate for the given class.
5412 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5414 MONO_REQ_GC_NEUTRAL_MODE;
5416 *pass_size_in_words = FALSE;
5418 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5419 return ves_icall_object_new_specific;
5421 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5423 return ves_icall_object_new_fast;
5426 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5427 * of the overhead of parameter passing.
5430 *pass_size_in_words = TRUE;
5431 #ifdef GC_REDIRECT_TO_LOCAL
5432 return GC_local_gcj_fast_malloc;
5434 return GC_gcj_fast_malloc;
5439 return ves_icall_object_new_specific;
5443 * mono_object_new_from_token:
5444 * \param image Context where the type_token is hosted
5445 * \param token a token of the type that we want to create
5446 * \returns A newly created object whose definition is
5447 * looked up using \p token in the \p image image
5450 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5452 MONO_REQ_GC_UNSAFE_MODE;
5458 klass = mono_class_get_checked (image, token, &error);
5459 mono_error_assert_ok (&error);
5461 result = mono_object_new_checked (domain, klass, &error);
5463 mono_error_cleanup (&error);
5470 * mono_object_clone:
5471 * \param obj the object to clone
5472 * \returns A newly created object who is a shallow copy of \p obj
5475 mono_object_clone (MonoObject *obj)
5478 MonoObject *o = mono_object_clone_checked (obj, &error);
5479 mono_error_cleanup (&error);
5485 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5487 MONO_REQ_GC_UNSAFE_MODE;
5494 size = obj->vtable->klass->instance_size;
5496 if (obj->vtable->klass->rank)
5497 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5499 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5501 if (G_UNLIKELY (!o)) {
5502 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5506 /* If the object doesn't contain references this will do a simple memmove. */
5507 mono_gc_wbarrier_object_copy (o, obj);
5509 if (obj->vtable->klass->has_finalize)
5510 mono_object_register_finalizer (o);
5515 * mono_array_full_copy:
5516 * \param src source array to copy
5517 * \param dest destination array
5518 * Copies the content of one array to another with exactly the same type and size.
5521 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5523 MONO_REQ_GC_UNSAFE_MODE;
5526 MonoClass *klass = src->obj.vtable->klass;
5528 g_assert (klass == dest->obj.vtable->klass);
5530 size = mono_array_length (src);
5531 g_assert (size == mono_array_length (dest));
5532 size *= mono_array_element_size (klass);
5534 array_full_copy_unchecked_size (src, dest, klass, size);
5538 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5541 if (klass->element_class->valuetype) {
5542 if (klass->element_class->has_references)
5543 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5545 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5547 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5550 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5555 * mono_array_clone_in_domain:
5556 * \param domain the domain in which the array will be cloned into
5557 * \param array the array to clone
5558 * \param error set on error
5559 * This routine returns a copy of the array that is hosted on the
5560 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5563 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5565 MONO_REQ_GC_UNSAFE_MODE;
5567 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5569 MonoClass *klass = mono_handle_class (array_handle);
5573 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5574 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5576 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5578 if (array_bounds == NULL) {
5579 size = mono_array_handle_length (array_handle);
5580 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5583 size *= mono_array_element_size (klass);
5585 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5586 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5587 size = mono_array_element_size (klass);
5588 for (int i = 0; i < klass->rank; ++i) {
5589 sizes [i] = array_bounds [i].length;
5590 size *= array_bounds [i].length;
5591 lower_bounds [i] = array_bounds [i].lower_bound;
5593 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5598 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5599 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5600 mono_gchandle_free (dst_handle);
5602 MONO_HANDLE_ASSIGN (result, o);
5605 mono_gchandle_free (src_handle);
5611 * \param array the array to clone
5612 * \returns A newly created array who is a shallow copy of \p array
5615 mono_array_clone (MonoArray *array)
5617 MONO_REQ_GC_UNSAFE_MODE;
5620 MonoArray *result = mono_array_clone_checked (array, &error);
5621 mono_error_cleanup (&error);
5626 * mono_array_clone_checked:
5627 * \param array the array to clone
5628 * \param error set on error
5629 * \returns A newly created array who is a shallow copy of \p array. On
5630 * failure returns NULL and sets \p error.
5633 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5635 MONO_REQ_GC_UNSAFE_MODE;
5636 HANDLE_FUNCTION_ENTER ();
5637 /* FIXME: callers of mono_array_clone_checked should use handles */
5639 MONO_HANDLE_DCL (MonoArray, array);
5640 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5641 HANDLE_FUNCTION_RETURN_OBJ (result);
5644 /* helper macros to check for overflow when calculating the size of arrays */
5645 #ifdef MONO_BIG_ARRAYS
5646 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5647 #define MYGUINT_MAX MYGUINT64_MAX
5648 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5649 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5650 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5651 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5652 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5654 #define MYGUINT32_MAX 4294967295U
5655 #define MYGUINT_MAX MYGUINT32_MAX
5656 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5657 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5658 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5659 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5660 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5664 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5666 MONO_REQ_GC_NEUTRAL_MODE;
5670 byte_len = mono_array_element_size (klass);
5671 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5674 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5676 byte_len += MONO_SIZEOF_MONO_ARRAY;
5684 * mono_array_new_full:
5685 * \param domain domain where the object is created
5686 * \param array_class array class
5687 * \param lengths lengths for each dimension in the array
5688 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5689 * This routine creates a new array object with the given dimensions,
5690 * lower bounds and type.
5693 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5696 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5697 mono_error_cleanup (&error);
5703 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5705 MONO_REQ_GC_UNSAFE_MODE;
5707 uintptr_t byte_len = 0, len, bounds_size;
5710 MonoArrayBounds *bounds;
5716 if (!array_class->inited)
5717 mono_class_init (array_class);
5721 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5722 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5724 if (len > MONO_ARRAY_MAX_INDEX) {
5725 mono_error_set_generic_error (error, "System", "OverflowException", "");
5730 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5732 for (i = 0; i < array_class->rank; ++i) {
5733 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5734 mono_error_set_generic_error (error, "System", "OverflowException", "");
5737 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5738 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5745 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5746 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5752 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5753 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5756 byte_len = (byte_len + 3) & ~3;
5757 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5758 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5761 byte_len += bounds_size;
5764 * Following three lines almost taken from mono_object_new ():
5765 * they need to be kept in sync.
5767 vtable = mono_class_vtable_full (domain, array_class, error);
5768 return_val_if_nok (error, NULL);
5771 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5773 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5775 if (G_UNLIKELY (!o)) {
5776 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5780 array = (MonoArray*)o;
5782 bounds = array->bounds;
5785 for (i = 0; i < array_class->rank; ++i) {
5786 bounds [i].length = lengths [i];
5788 bounds [i].lower_bound = lower_bounds [i];
5797 * \param domain domain where the object is created
5798 * \param eclass element class
5799 * \param n number of array elements
5800 * This routine creates a new szarray with \p n elements of type \p eclass.
5803 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5805 MONO_REQ_GC_UNSAFE_MODE;
5808 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5809 mono_error_cleanup (&error);
5814 * mono_array_new_checked:
5815 * \param domain domain where the object is created
5816 * \param eclass element class
5817 * \param n number of array elements
5818 * \param error set on error
5819 * This routine creates a new szarray with \p n elements of type \p eclass.
5820 * On failure returns NULL and sets \p error.
5823 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5829 ac = mono_array_class_get (eclass, 1);
5832 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5833 return_val_if_nok (error, NULL);
5835 return mono_array_new_specific_checked (vtable, n, error);
5839 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5842 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5843 mono_error_set_pending_exception (&error);
5849 * mono_array_new_specific:
5850 * \param vtable a vtable in the appropriate domain for an initialized class
5851 * \param n number of array elements
5852 * This routine is a fast alternative to \c mono_array_new for code which
5853 * can be sure about the domain it operates in.
5856 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5859 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5860 mono_error_cleanup (&error);
5866 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5868 MONO_REQ_GC_UNSAFE_MODE;
5875 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5876 mono_error_set_generic_error (error, "System", "OverflowException", "");
5880 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5881 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5884 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5886 if (G_UNLIKELY (!o)) {
5887 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5891 return (MonoArray*)o;
5895 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5898 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5899 mono_error_set_pending_exception (&error);
5905 * mono_string_empty_wrapper:
5907 * Returns: The same empty string instance as the managed string.Empty
5910 mono_string_empty_wrapper (void)
5912 MonoDomain *domain = mono_domain_get ();
5913 return mono_string_empty (domain);
5917 * mono_string_empty:
5919 * Returns: The same empty string instance as the managed string.Empty
5922 mono_string_empty (MonoDomain *domain)
5925 g_assert (domain->empty_string);
5926 return domain->empty_string;
5930 * mono_string_new_utf16:
5931 * \param text a pointer to an utf16 string
5932 * \param len the length of the string
5933 * \returns A newly created string object which contains \p text.
5936 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5938 MONO_REQ_GC_UNSAFE_MODE;
5941 MonoString *res = NULL;
5942 res = mono_string_new_utf16_checked (domain, text, len, &error);
5943 mono_error_cleanup (&error);
5949 * mono_string_new_utf16_checked:
5950 * \param text a pointer to an utf16 string
5951 * \param len the length of the string
5952 * \param error written on error.
5953 * \returns A newly created string object which contains \p text.
5954 * On error, returns NULL and sets \p error.
5957 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5959 MONO_REQ_GC_UNSAFE_MODE;
5965 s = mono_string_new_size_checked (domain, len, error);
5967 memcpy (mono_string_chars (s), text, len * 2);
5973 * mono_string_new_utf16_handle:
5974 * \param text a pointer to an utf16 string
5975 * \param len the length of the string
5976 * \param error written on error.
5977 * \returns A newly created string object which contains \p text.
5978 * On error, returns NULL and sets \p error.
5981 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5983 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
5987 * mono_string_new_utf32_checked:
5988 * \param text a pointer to an utf32 string
5989 * \param len the length of the string
5990 * \param error set on failure.
5991 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
5994 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5996 MONO_REQ_GC_UNSAFE_MODE;
5999 mono_unichar2 *utf16_output = NULL;
6000 gint32 utf16_len = 0;
6001 GError *gerror = NULL;
6002 glong items_written;
6005 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6008 g_error_free (gerror);
6010 while (utf16_output [utf16_len]) utf16_len++;
6012 s = mono_string_new_size_checked (domain, utf16_len, error);
6013 return_val_if_nok (error, NULL);
6015 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6017 g_free (utf16_output);
6023 * mono_string_new_utf32:
6024 * \param text a pointer to a UTF-32 string
6025 * \param len the length of the string
6026 * \returns A newly created string object which contains \p text.
6029 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6032 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6033 mono_error_cleanup (&error);
6038 * mono_string_new_size:
6039 * \param text a pointer to a UTF-16 string
6040 * \param len the length of the string
6041 * \returns A newly created string object of \p len
6044 mono_string_new_size (MonoDomain *domain, gint32 len)
6047 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6048 mono_error_cleanup (&error);
6054 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6056 MONO_REQ_GC_UNSAFE_MODE;
6064 /* check for overflow */
6065 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6066 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6070 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6071 g_assert (size > 0);
6073 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6076 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6078 if (G_UNLIKELY (!s)) {
6079 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6087 * mono_string_new_len:
6088 * \param text a pointer to an utf8 string
6089 * \param length number of bytes in \p text to consider
6090 * \returns A newly created string object which contains \p text.
6093 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6095 MONO_REQ_GC_UNSAFE_MODE;
6098 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6099 mono_error_cleanup (&error);
6104 * mono_string_new_len_checked:
6105 * \param text a pointer to an utf8 string
6106 * \param length number of bytes in \p text to consider
6107 * \param error set on error
6108 * \returns A newly created string object which contains \p text. On
6109 * failure returns NULL and sets \p error.
6112 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6114 MONO_REQ_GC_UNSAFE_MODE;
6118 GError *eg_error = NULL;
6119 MonoString *o = NULL;
6121 glong items_written;
6123 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6126 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6128 g_error_free (eg_error);
6137 * \param text a pointer to a UTF-8 string
6138 * \deprecated Use \c mono_string_new_checked in new code.
6139 * This function asserts if it cannot allocate a new string.
6140 * \returns A newly created string object which contains \p text.
6143 mono_string_new (MonoDomain *domain, const char *text)
6146 MonoString *res = NULL;
6147 res = mono_string_new_checked (domain, text, &error);
6148 mono_error_assert_ok (&error);
6153 * mono_string_new_checked:
6154 * \param text a pointer to an utf8 string
6155 * \param merror set on error
6156 * \returns A newly created string object which contains \p text.
6157 * On error returns NULL and sets \p merror.
6160 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6162 MONO_REQ_GC_UNSAFE_MODE;
6164 GError *eg_error = NULL;
6165 MonoString *o = NULL;
6167 glong items_written;
6174 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6177 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6179 g_error_free (eg_error);
6183 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6188 MonoString *o = NULL;
6190 if (!g_utf8_validate (text, -1, &end)) {
6191 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6195 len = g_utf8_strlen (text, -1);
6196 o = mono_string_new_size_checked (domain, len, error);
6199 str = mono_string_chars (o);
6201 while (text < end) {
6202 *str++ = g_utf8_get_char (text);
6203 text = g_utf8_next_char (text);
6212 * mono_string_new_wrapper:
6213 * \param text pointer to UTF-8 characters.
6214 * Helper function to create a string object from \p text in the current domain.
6217 mono_string_new_wrapper (const char *text)
6219 MONO_REQ_GC_UNSAFE_MODE;
6221 MonoDomain *domain = mono_domain_get ();
6224 return mono_string_new (domain, text);
6231 * \param class the class of the value
6232 * \param value a pointer to the unboxed data
6233 * \returns A newly created object which contains \p value.
6236 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6239 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6240 mono_error_cleanup (&error);
6245 * mono_value_box_checked:
6246 * \param domain the domain of the new object
6247 * \param class the class of the value
6248 * \param value a pointer to the unboxed data
6249 * \param error set on error
6250 * \returns A newly created object which contains \p value. On failure
6251 * returns NULL and sets \p error.
6254 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6256 MONO_REQ_GC_UNSAFE_MODE;
6263 g_assert (klass->valuetype);
6264 if (mono_class_is_nullable (klass))
6265 return mono_nullable_box ((guint8 *)value, klass, error);
6267 vtable = mono_class_vtable (domain, klass);
6270 size = mono_class_instance_size (klass);
6271 res = mono_object_new_alloc_specific_checked (vtable, error);
6272 return_val_if_nok (error, NULL);
6274 size = size - sizeof (MonoObject);
6277 g_assert (size == mono_class_value_size (klass, NULL));
6278 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6280 #if NO_UNALIGNED_ACCESS
6281 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6285 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6288 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6291 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6294 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6297 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6301 if (klass->has_finalize) {
6302 mono_object_register_finalizer (res);
6303 return_val_if_nok (error, NULL);
6310 * \param dest destination pointer
6311 * \param src source pointer
6312 * \param klass a valuetype class
6313 * Copy a valuetype from \p src to \p dest. This function must be used
6314 * when \p klass contains reference fields.
6317 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6319 MONO_REQ_GC_UNSAFE_MODE;
6321 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6325 * mono_value_copy_array:
6326 * \param dest destination array
6327 * \param dest_idx index in the \p dest array
6328 * \param src source pointer
6329 * \param count number of items
6330 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6331 * This function must be used when \p klass contains references fields.
6332 * Overlap is handled.
6335 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6337 MONO_REQ_GC_UNSAFE_MODE;
6339 int size = mono_array_element_size (dest->obj.vtable->klass);
6340 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6341 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6342 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6346 * mono_object_get_domain:
6347 * \param obj object to query
6348 * \returns the \c MonoDomain where the object is hosted
6351 mono_object_get_domain (MonoObject *obj)
6353 MONO_REQ_GC_UNSAFE_MODE;
6355 return mono_object_domain (obj);
6359 * mono_object_get_class:
6360 * \param obj object to query
6361 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6362 * \returns the \c MonoClass of the object.
6365 mono_object_get_class (MonoObject *obj)
6367 MONO_REQ_GC_UNSAFE_MODE;
6369 return mono_object_class (obj);
6372 * mono_object_get_size:
6373 * \param o object to query
6374 * \returns the size, in bytes, of \p o
6377 mono_object_get_size (MonoObject* o)
6379 MONO_REQ_GC_UNSAFE_MODE;
6381 MonoClass* klass = mono_object_class (o);
6382 if (klass == mono_defaults.string_class) {
6383 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6384 } else if (o->vtable->rank) {
6385 MonoArray *array = (MonoArray*)o;
6386 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6387 if (array->bounds) {
6390 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6394 return mono_class_instance_size (klass);
6399 * mono_object_unbox:
6400 * \param obj object to unbox
6401 * \returns a pointer to the start of the valuetype boxed in this
6404 * This method will assert if the object passed is not a valuetype.
6407 mono_object_unbox (MonoObject *obj)
6409 MONO_REQ_GC_UNSAFE_MODE;
6411 /* add assert for valuetypes? */
6412 g_assert (obj->vtable->klass->valuetype);
6413 return ((char*)obj) + sizeof (MonoObject);
6417 * mono_object_isinst:
6418 * \param obj an object
6419 * \param klass a pointer to a class
6420 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6423 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6425 MONO_REQ_GC_UNSAFE_MODE;
6427 HANDLE_FUNCTION_ENTER ();
6428 MONO_HANDLE_DCL (MonoObject, obj);
6430 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6431 mono_error_cleanup (&error);
6432 HANDLE_FUNCTION_RETURN_OBJ (result);
6437 * mono_object_isinst_checked:
6438 * \param obj an object
6439 * \param klass a pointer to a class
6440 * \param error set on error
6441 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6442 * On failure returns NULL and sets \p error.
6445 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6447 MONO_REQ_GC_UNSAFE_MODE;
6449 HANDLE_FUNCTION_ENTER ();
6451 MONO_HANDLE_DCL (MonoObject, obj);
6452 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6453 HANDLE_FUNCTION_RETURN_OBJ (result);
6457 * mono_object_handle_isinst:
6458 * \param obj an object
6459 * \param klass a pointer to a class
6460 * \param error set on error
6461 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6462 * On failure returns NULL and sets \p error.
6465 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6470 mono_class_init (klass);
6472 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6473 return mono_object_handle_isinst_mbyref (obj, klass, error);
6476 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6478 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6479 MONO_HANDLE_ASSIGN (result, obj);
6484 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6486 MONO_REQ_GC_UNSAFE_MODE;
6488 HANDLE_FUNCTION_ENTER ();
6490 MONO_HANDLE_DCL (MonoObject, obj);
6491 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6492 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6493 HANDLE_FUNCTION_RETURN_OBJ (result);
6497 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6501 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6503 if (MONO_HANDLE_IS_NULL (obj))
6506 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6508 if (mono_class_is_interface (klass)) {
6509 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6510 MONO_HANDLE_ASSIGN (result, obj);
6514 /* casting an array one of the invariant interfaces that must act as such */
6515 if (klass->is_array_special_interface) {
6516 if (mono_class_is_assignable_from (klass, vt->klass)) {
6517 MONO_HANDLE_ASSIGN (result, obj);
6522 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6523 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6524 MONO_HANDLE_ASSIGN (result, obj);
6528 MonoClass *oklass = vt->klass;
6529 if (mono_class_is_transparent_proxy (oklass)){
6530 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6531 oklass = remote_class->proxy_class;
6534 mono_class_setup_supertypes (klass);
6535 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6536 MONO_HANDLE_ASSIGN (result, obj);
6540 #ifndef DISABLE_REMOTING
6541 if (mono_class_is_transparent_proxy (vt->klass))
6543 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6544 if (!custom_type_info)
6546 MonoDomain *domain = mono_domain_get ();
6547 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6548 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6549 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6550 MonoMethod *im = NULL;
6553 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6555 mono_error_set_not_supported (error, "Linked away.");
6558 im = mono_object_handle_get_virtual_method (rp, im, error);
6563 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6567 pa [0] = MONO_HANDLE_RAW (reftype);
6568 pa [1] = MONO_HANDLE_RAW (obj);
6569 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6573 if (*(MonoBoolean *) mono_object_unbox(res)) {
6574 /* Update the vtable of the remote type, so it can safely cast to this new type */
6575 mono_upgrade_remote_class (domain, obj, klass, error);
6578 MONO_HANDLE_ASSIGN (result, obj);
6581 #endif /* DISABLE_REMOTING */
6587 * mono_object_castclass_mbyref:
6588 * \param obj an object
6589 * \param klass a pointer to a class
6590 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6593 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6595 MONO_REQ_GC_UNSAFE_MODE;
6596 HANDLE_FUNCTION_ENTER ();
6598 MONO_HANDLE_DCL (MonoObject, obj);
6599 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6600 if (MONO_HANDLE_IS_NULL (obj))
6602 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6603 mono_error_cleanup (&error);
6605 HANDLE_FUNCTION_RETURN_OBJ (result);
6609 MonoDomain *orig_domain;
6615 str_lookup (MonoDomain *domain, gpointer user_data)
6617 MONO_REQ_GC_UNSAFE_MODE;
6619 LDStrInfo *info = (LDStrInfo *)user_data;
6620 if (info->res || domain == info->orig_domain)
6622 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6626 mono_string_get_pinned (MonoString *str, MonoError *error)
6628 MONO_REQ_GC_UNSAFE_MODE;
6632 /* We only need to make a pinned version of a string if this is a moving GC */
6633 if (!mono_gc_is_moving ())
6637 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6638 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6640 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6641 news->length = mono_string_length (str);
6643 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6649 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6651 MONO_REQ_GC_UNSAFE_MODE;
6653 MonoGHashTable *ldstr_table;
6654 MonoString *s, *res;
6659 domain = ((MonoObject *)str)->vtable->domain;
6660 ldstr_table = domain->ldstr_table;
6662 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6668 /* Allocate outside the lock */
6670 s = mono_string_get_pinned (str, error);
6671 return_val_if_nok (error, NULL);
6674 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6679 mono_g_hash_table_insert (ldstr_table, s, s);
6684 LDStrInfo ldstr_info;
6685 ldstr_info.orig_domain = domain;
6686 ldstr_info.ins = str;
6687 ldstr_info.res = NULL;
6689 mono_domain_foreach (str_lookup, &ldstr_info);
6690 if (ldstr_info.res) {
6692 * the string was already interned in some other domain:
6693 * intern it in the current one as well.
6695 mono_g_hash_table_insert (ldstr_table, str, str);
6705 * mono_string_is_interned:
6706 * \param o String to probe
6707 * \returns Whether the string has been interned.
6710 mono_string_is_interned (MonoString *o)
6713 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6714 /* This function does not fail. */
6715 mono_error_assert_ok (&error);
6720 * mono_string_intern:
6721 * \param o String to intern
6722 * Interns the string passed.
6723 * \returns The interned string.
6726 mono_string_intern (MonoString *str)
6729 MonoString *result = mono_string_intern_checked (str, &error);
6730 mono_error_assert_ok (&error);
6735 * mono_string_intern_checked:
6736 * \param o String to intern
6737 * \param error set on error.
6738 * Interns the string passed.
6739 * \returns The interned string. On failure returns NULL and sets \p error
6742 mono_string_intern_checked (MonoString *str, MonoError *error)
6744 MONO_REQ_GC_UNSAFE_MODE;
6748 return mono_string_is_interned_lookup (str, TRUE, error);
6753 * \param domain the domain where the string will be used.
6754 * \param image a metadata context
6755 * \param idx index into the user string table.
6756 * Implementation for the \c ldstr opcode.
6757 * \returns a loaded string from the \p image / \p idx combination.
6760 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6763 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6764 mono_error_cleanup (&error);
6769 * mono_ldstr_checked:
6770 * \param domain the domain where the string will be used.
6771 * \param image a metadata context
6772 * \param idx index into the user string table.
6773 * \param error set on error.
6774 * Implementation for the \c ldstr opcode.
6775 * \returns A loaded string from the \p image / \p idx combination.
6776 * On failure returns NULL and sets \p error.
6779 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6781 MONO_REQ_GC_UNSAFE_MODE;
6784 if (image->dynamic) {
6785 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6788 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6789 return NULL; /*FIXME we should probably be raising an exception here*/
6790 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6796 * mono_ldstr_metadata_sig
6797 * \param domain the domain for the string
6798 * \param sig the signature of a metadata string
6799 * \param error set on error
6800 * \returns a \c MonoString for a string stored in the metadata. On
6801 * failure returns NULL and sets \p error.
6804 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6806 MONO_REQ_GC_UNSAFE_MODE;
6809 const char *str = sig;
6810 MonoString *o, *interned;
6813 len2 = mono_metadata_decode_blob_size (str, &str);
6816 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6817 return_val_if_nok (error, NULL);
6818 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6821 guint16 *p2 = (guint16*)mono_string_chars (o);
6822 for (i = 0; i < len2; ++i) {
6823 *p2 = GUINT16_FROM_LE (*p2);
6829 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6832 return interned; /* o will get garbage collected */
6834 o = mono_string_get_pinned (o, error);
6837 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6839 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6851 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6855 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6861 GError *gerror = NULL;
6865 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6866 return NULL; /*FIXME we should probably be raising an exception here*/
6867 str = mono_metadata_user_string (image, idx);
6869 len2 = mono_metadata_decode_blob_size (str, &str);
6872 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6874 mono_error_set_argument (error, "string", "%s", gerror->message);
6875 g_error_free (gerror);
6878 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6879 if (len2 > written) {
6880 /* allocate the total length and copy the part of the string that has been converted */
6881 char *as2 = (char *)g_malloc0 (len2);
6882 memcpy (as2, as, written);
6891 * mono_string_to_utf8:
6892 * \param s a \c System.String
6893 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6894 * \returns the UTF-8 representation for \p s.
6895 * The resulting buffer needs to be freed with \c mono_free().
6898 mono_string_to_utf8 (MonoString *s)
6900 MONO_REQ_GC_UNSAFE_MODE;
6903 char *result = mono_string_to_utf8_checked (s, &error);
6905 if (!is_ok (&error)) {
6906 mono_error_cleanup (&error);
6913 * mono_string_to_utf8_checked:
6914 * \param s a \c System.String
6915 * \param error a \c MonoError.
6916 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6917 * \p error to determine whether the conversion was successful.
6918 * The resulting buffer should be freed with \c mono_free().
6921 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6923 MONO_REQ_GC_UNSAFE_MODE;
6927 GError *gerror = NULL;
6935 return g_strdup ("");
6937 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6939 mono_error_set_argument (error, "string", "%s", gerror->message);
6940 g_error_free (gerror);
6943 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6944 if (s->length > written) {
6945 /* allocate the total length and copy the part of the string that has been converted */
6946 char *as2 = (char *)g_malloc0 (s->length);
6947 memcpy (as2, as, written);
6956 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6958 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6962 * mono_string_to_utf8_ignore:
6963 * \param s a MonoString
6964 * Converts a \c MonoString to its UTF-8 representation. Will ignore
6965 * invalid surrogate pairs.
6966 * The resulting buffer should be freed with \c mono_free().
6969 mono_string_to_utf8_ignore (MonoString *s)
6971 MONO_REQ_GC_UNSAFE_MODE;
6980 return g_strdup ("");
6982 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6984 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6985 if (s->length > written) {
6986 /* allocate the total length and copy the part of the string that has been converted */
6987 char *as2 = (char *)g_malloc0 (s->length);
6988 memcpy (as2, as, written);
6997 * mono_string_to_utf8_image_ignore:
6998 * \param s a \c System.String
6999 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7002 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7004 MONO_REQ_GC_UNSAFE_MODE;
7006 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7010 * mono_string_to_utf8_mp_ignore:
7011 * \param s a \c System.String
7012 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7015 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7017 MONO_REQ_GC_UNSAFE_MODE;
7019 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7024 * mono_string_to_utf16:
7025 * \param s a \c MonoString
7026 * \returns a null-terminated array of the UTF-16 chars
7027 * contained in \param s. The result must be freed with \c g_free().
7028 * This is a temporary helper until our string implementation
7029 * is reworked to always include the null-terminating char.
7032 mono_string_to_utf16 (MonoString *s)
7034 MONO_REQ_GC_UNSAFE_MODE;
7041 as = (char *)g_malloc ((s->length * 2) + 2);
7042 as [(s->length * 2)] = '\0';
7043 as [(s->length * 2) + 1] = '\0';
7046 return (gunichar2 *)(as);
7049 memcpy (as, mono_string_chars(s), s->length * 2);
7050 return (gunichar2 *)(as);
7054 * mono_string_to_utf32:
7055 * \param s a \c MonoString
7056 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7057 * contained in \p s. The result must be freed with \c g_free().
7060 mono_string_to_utf32 (MonoString *s)
7062 MONO_REQ_GC_UNSAFE_MODE;
7064 mono_unichar4 *utf32_output = NULL;
7065 GError *error = NULL;
7066 glong items_written;
7071 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7074 g_error_free (error);
7076 return utf32_output;
7080 * mono_string_from_utf16:
7081 * \param data the UTF-16 string (LPWSTR) to convert
7082 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7083 * \returns a \c MonoString.
7086 mono_string_from_utf16 (gunichar2 *data)
7089 MonoString *result = mono_string_from_utf16_checked (data, &error);
7090 mono_error_cleanup (&error);
7095 * mono_string_from_utf16_checked:
7096 * \param data the UTF-16 string (LPWSTR) to convert
7097 * \param error set on error
7098 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7099 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7102 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7105 MONO_REQ_GC_UNSAFE_MODE;
7108 MonoDomain *domain = mono_domain_get ();
7114 while (data [len]) len++;
7116 return mono_string_new_utf16_checked (domain, data, len, error);
7120 * mono_string_from_utf32:
7121 * \param data the UTF-32 string (LPWSTR) to convert
7122 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7123 * \returns a \c MonoString.
7126 mono_string_from_utf32 (mono_unichar4 *data)
7129 MonoString *result = mono_string_from_utf32_checked (data, &error);
7130 mono_error_cleanup (&error);
7135 * mono_string_from_utf32_checked:
7136 * \param data the UTF-32 string (LPWSTR) to convert
7137 * \param error set on error
7138 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7139 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7142 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7144 MONO_REQ_GC_UNSAFE_MODE;
7147 MonoString* result = NULL;
7148 mono_unichar2 *utf16_output = NULL;
7149 GError *gerror = NULL;
7150 glong items_written;
7156 while (data [len]) len++;
7158 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7161 g_error_free (gerror);
7163 result = mono_string_from_utf16_checked (utf16_output, error);
7164 g_free (utf16_output);
7169 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7171 MONO_REQ_GC_UNSAFE_MODE;
7178 r = mono_string_to_utf8_ignore (s);
7180 r = mono_string_to_utf8_checked (s, error);
7181 if (!mono_error_ok (error))
7188 len = strlen (r) + 1;
7190 mp_s = (char *)mono_mempool_alloc (mp, len);
7192 mp_s = (char *)mono_image_alloc (image, len);
7194 memcpy (mp_s, r, len);
7202 * mono_string_to_utf8_image:
7203 * \param s a \c System.String
7204 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7207 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7209 MONO_REQ_GC_UNSAFE_MODE;
7211 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7215 * mono_string_to_utf8_mp:
7216 * \param s a \c System.String
7217 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7220 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7222 MONO_REQ_GC_UNSAFE_MODE;
7224 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7228 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7231 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7233 eh_callbacks = *cbs;
7236 MonoRuntimeExceptionHandlingCallbacks *
7237 mono_get_eh_callbacks (void)
7239 return &eh_callbacks;
7243 * mono_raise_exception:
7244 * \param ex exception object
7245 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7248 mono_raise_exception (MonoException *ex)
7250 MONO_REQ_GC_UNSAFE_MODE;
7253 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7254 * that will cause gcc to omit the function epilog, causing problems when
7255 * the JIT tries to walk the stack, since the return address on the stack
7256 * will point into the next function in the executable, not this one.
7258 eh_callbacks.mono_raise_exception (ex);
7262 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7264 MONO_REQ_GC_UNSAFE_MODE;
7266 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7270 * mono_wait_handle_new:
7271 * \param domain Domain where the object will be created
7272 * \param handle Handle for the wait handle
7273 * \param error set on error.
7274 * \returns A new \c MonoWaitHandle created in the given domain for the
7275 * given handle. On failure returns NULL and sets \p error.
7278 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7280 MONO_REQ_GC_UNSAFE_MODE;
7282 MonoWaitHandle *res;
7283 gpointer params [1];
7284 static MonoMethod *handle_set;
7287 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7288 return_val_if_nok (error, NULL);
7290 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7292 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7294 params [0] = &handle;
7296 mono_runtime_invoke_checked (handle_set, res, params, error);
7301 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7303 MONO_REQ_GC_UNSAFE_MODE;
7305 static MonoClassField *f_safe_handle = NULL;
7308 if (!f_safe_handle) {
7309 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7310 g_assert (f_safe_handle);
7313 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7319 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7321 MONO_REQ_GC_UNSAFE_MODE;
7323 RuntimeInvokeFunction runtime_invoke;
7327 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7328 MonoMethod *method = mono_get_context_capture_method ();
7329 MonoMethod *wrapper;
7332 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7333 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7334 return_val_if_nok (error, NULL);
7335 domain->capture_context_method = mono_compile_method_checked (method, error);
7336 return_val_if_nok (error, NULL);
7339 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7341 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7344 * mono_async_result_new:
7345 * \param domain domain where the object will be created.
7346 * \param handle wait handle.
7347 * \param state state to pass to AsyncResult
7348 * \param data C closure data.
7349 * \param error set on error.
7350 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7351 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7352 * On failure returns NULL and sets \p error.
7355 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7357 MONO_REQ_GC_UNSAFE_MODE;
7360 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7361 return_val_if_nok (error, NULL);
7362 MonoObject *context = mono_runtime_capture_context (domain, error);
7363 return_val_if_nok (error, NULL);
7364 /* we must capture the execution context from the original thread */
7366 MONO_OBJECT_SETREF (res, execution_context, context);
7367 /* note: result may be null if the flow is suppressed */
7370 res->data = (void **)data;
7371 MONO_OBJECT_SETREF (res, object_data, object_data);
7372 MONO_OBJECT_SETREF (res, async_state, state);
7373 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7374 return_val_if_nok (error, NULL);
7376 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7378 res->sync_completed = FALSE;
7379 res->completed = FALSE;
7385 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7387 MONO_REQ_GC_UNSAFE_MODE;
7394 g_assert (ares->async_delegate);
7396 ac = (MonoAsyncCall*) ares->object_data;
7398 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7399 if (mono_error_set_pending_exception (&error))
7402 gpointer wait_event = NULL;
7404 ac->msg->exc = NULL;
7406 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7408 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7409 mono_threads_begin_abort_protected_block ();
7411 if (!ac->msg->exc) {
7412 MonoException *ex = mono_error_convert_to_exception (&error);
7413 ac->msg->exc = (MonoObject *)ex;
7415 mono_error_cleanup (&error);
7418 MONO_OBJECT_SETREF (ac, res, res);
7420 mono_monitor_enter ((MonoObject*) ares);
7421 ares->completed = 1;
7423 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7424 mono_monitor_exit ((MonoObject*) ares);
7426 if (wait_event != NULL)
7427 mono_w32event_set (wait_event);
7429 error_init (&error); //the else branch would leave it in an undefined state
7431 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7433 mono_threads_end_abort_protected_block ();
7435 if (mono_error_set_pending_exception (&error))
7443 mono_message_init (MonoDomain *domain,
7444 MonoMethodMessage *this_obj,
7445 MonoReflectionMethod *method,
7446 MonoArray *out_args,
7449 MONO_REQ_GC_UNSAFE_MODE;
7451 static MonoMethod *init_message_method = NULL;
7453 if (!init_message_method) {
7454 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7455 g_assert (init_message_method != NULL);
7459 /* FIXME set domain instead? */
7460 g_assert (domain == mono_domain_get ());
7467 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7468 return is_ok (error);
7471 #ifndef DISABLE_REMOTING
7473 * mono_remoting_invoke:
7474 * \param real_proxy pointer to a \c RealProxy object
7475 * \param msg The \c MonoMethodMessage to execute
7476 * \param exc used to store exceptions
7477 * \param out_args used to store output arguments
7478 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7479 * \c IMessage interface and it is not trivial to extract results from there. So
7480 * we call an helper method \c PrivateInvoke instead of calling
7481 * \c RealProxy::Invoke() directly.
7482 * \returns the result object.
7485 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7487 MONO_REQ_GC_UNSAFE_MODE;
7490 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7497 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7500 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7502 mono_error_set_not_supported (error, "Linked away.");
7505 real_proxy->vtable->domain->private_invoke_method = im;
7508 pa [0] = real_proxy;
7513 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7514 return_val_if_nok (error, NULL);
7521 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7522 MonoObject **exc, MonoArray **out_args, MonoError *error)
7524 MONO_REQ_GC_UNSAFE_MODE;
7526 static MonoClass *object_array_klass;
7531 MonoMethodSignature *sig;
7533 int i, j, outarg_count = 0;
7535 #ifndef DISABLE_REMOTING
7536 if (target && mono_object_is_transparent_proxy (target)) {
7537 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7538 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7539 target = tp->rp->unwrapped_server;
7541 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7546 domain = mono_domain_get ();
7547 method = msg->method->method;
7548 sig = mono_method_signature (method);
7550 for (i = 0; i < sig->param_count; i++) {
7551 if (sig->params [i]->byref)
7555 if (!object_array_klass) {
7558 klass = mono_array_class_get (mono_defaults.object_class, 1);
7561 mono_memory_barrier ();
7562 object_array_klass = klass;
7565 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7566 return_val_if_nok (error, NULL);
7568 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7571 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7572 return_val_if_nok (error, NULL);
7574 for (i = 0, j = 0; i < sig->param_count; i++) {
7575 if (sig->params [i]->byref) {
7577 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7578 mono_array_setref (*out_args, j, arg);
7587 * prepare_to_string_method:
7589 * @target: Set to @obj or unboxed value if a valuetype
7591 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7594 prepare_to_string_method (MonoObject *obj, void **target)
7596 MONO_REQ_GC_UNSAFE_MODE;
7598 static MonoMethod *to_string = NULL;
7606 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7608 method = mono_object_get_virtual_method (obj, to_string);
7610 // Unbox value type if needed
7611 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7612 *target = mono_object_unbox (obj);
7618 * mono_object_to_string:
7619 * \param obj The object
7620 * \param exc Any exception thrown by \c ToString(). May be NULL.
7621 * \returns the result of calling \c ToString() on an object.
7624 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7627 MonoString *s = NULL;
7629 MonoMethod *method = prepare_to_string_method (obj, &target);
7631 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7632 if (*exc == NULL && !mono_error_ok (&error))
7633 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7635 mono_error_cleanup (&error);
7637 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7638 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7645 * mono_object_to_string_checked:
7646 * \param obj The object
7647 * \param error Set on error.
7648 * \returns the result of calling \c ToString() on an object. If the
7649 * method cannot be invoked or if it raises an exception, sets \p error
7653 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7657 MonoMethod *method = prepare_to_string_method (obj, &target);
7658 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7662 * mono_object_try_to_string:
7663 * \param obj The object
7664 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7665 * \param error Set if method cannot be invoked.
7666 * \returns the result of calling \c ToString() on an object. If the
7667 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7671 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7676 MonoMethod *method = prepare_to_string_method (obj, &target);
7677 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7683 get_native_backtrace (MonoException *exc_raw)
7685 HANDLE_FUNCTION_ENTER ();
7686 MONO_HANDLE_DCL(MonoException, exc);
7687 char * trace = mono_exception_handle_get_native_backtrace (exc);
7688 HANDLE_FUNCTION_RETURN_VAL (trace);
7692 * mono_print_unhandled_exception:
7693 * \param exc The exception
7694 * Prints the unhandled exception.
7697 mono_print_unhandled_exception (MonoObject *exc)
7699 MONO_REQ_GC_UNSAFE_MODE;
7702 char *message = (char*)"";
7703 gboolean free_message = FALSE;
7706 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7707 message = g_strdup ("OutOfMemoryException");
7708 free_message = TRUE;
7709 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7710 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7711 free_message = TRUE;
7714 if (((MonoException*)exc)->native_trace_ips) {
7715 message = get_native_backtrace ((MonoException*)exc);
7716 free_message = TRUE;
7718 MonoObject *other_exc = NULL;
7719 str = mono_object_try_to_string (exc, &other_exc, &error);
7720 if (other_exc == NULL && !is_ok (&error))
7721 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7723 mono_error_cleanup (&error);
7725 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7726 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7728 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7729 original_backtrace, nested_backtrace);
7731 g_free (original_backtrace);
7732 g_free (nested_backtrace);
7733 free_message = TRUE;
7735 message = mono_string_to_utf8_checked (str, &error);
7736 if (!mono_error_ok (&error)) {
7737 mono_error_cleanup (&error);
7738 message = (char *) "";
7740 free_message = TRUE;
7747 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7748 * exc->vtable->klass->name, message);
7750 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7757 * mono_delegate_ctor_with_method:
7758 * \param this pointer to an uninitialized delegate object
7759 * \param target target object
7760 * \param addr pointer to native code
7761 * \param method method
7762 * \param error set on error.
7763 * Initialize a delegate and sets a specific method, not the one
7764 * associated with \p addr. This is useful when sharing generic code.
7765 * In that case \p addr will most probably not be associated with the
7766 * correct instantiation of the method.
7767 * On failure returns FALSE and sets \p error.
7770 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7772 MONO_REQ_GC_UNSAFE_MODE;
7775 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7777 g_assert (this_obj);
7780 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7783 delegate->method = method;
7785 mono_stats.delegate_creations++;
7787 #ifndef DISABLE_REMOTING
7788 if (target && mono_object_is_transparent_proxy (target)) {
7790 method = mono_marshal_get_remoting_invoke (method);
7791 #ifdef ENABLE_INTERPRETER
7792 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7794 delegate->method_ptr = mono_compile_method_checked (method, error);
7795 return_val_if_nok (error, FALSE);
7796 MONO_OBJECT_SETREF (delegate, target, target);
7800 delegate->method_ptr = addr;
7801 MONO_OBJECT_SETREF (delegate, target, target);
7804 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7805 if (callbacks.init_delegate)
7806 callbacks.init_delegate (delegate);
7811 * mono_delegate_ctor:
7812 * \param this pointer to an uninitialized delegate object
7813 * \param target target object
7814 * \param addr pointer to native code
7815 * \param error set on error.
7816 * This is used to initialize a delegate.
7817 * On failure returns FALSE and sets \p error.
7820 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7822 MONO_REQ_GC_UNSAFE_MODE;
7825 MonoDomain *domain = mono_domain_get ();
7827 MonoMethod *method = NULL;
7831 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7833 if (!ji && domain != mono_get_root_domain ())
7834 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7836 method = mono_jit_info_get_method (ji);
7837 g_assert (!mono_class_is_gtd (method->klass));
7840 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7844 * mono_method_call_message_new:
7845 * \param method method to encapsulate
7846 * \param params parameters to the method
7847 * \param invoke optional, delegate invoke.
7848 * \param cb async callback delegate.
7849 * \param state state passed to the async callback.
7850 * \param error set on error.
7851 * Translates arguments pointers into a \c MonoMethodMessage.
7852 * On failure returns NULL and sets \p error.
7855 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7856 MonoDelegate **cb, MonoObject **state, MonoError *error)
7858 MONO_REQ_GC_UNSAFE_MODE;
7862 MonoDomain *domain = mono_domain_get ();
7863 MonoMethodSignature *sig = mono_method_signature (method);
7864 MonoMethodMessage *msg;
7867 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7868 return_val_if_nok (error, NULL);
7871 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7872 return_val_if_nok (error, NULL);
7873 mono_message_init (domain, msg, rm, NULL, error);
7874 return_val_if_nok (error, NULL);
7875 count = sig->param_count - 2;
7877 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7878 return_val_if_nok (error, NULL);
7879 mono_message_init (domain, msg, rm, NULL, error);
7880 return_val_if_nok (error, NULL);
7881 count = sig->param_count;
7884 for (i = 0; i < count; i++) {
7889 if (sig->params [i]->byref)
7890 vpos = *((gpointer *)params [i]);
7894 klass = mono_class_from_mono_type (sig->params [i]);
7896 if (klass->valuetype) {
7897 arg = mono_value_box_checked (domain, klass, vpos, error);
7898 return_val_if_nok (error, NULL);
7900 arg = *((MonoObject **)vpos);
7902 mono_array_setref (msg->args, i, arg);
7905 if (cb != NULL && state != NULL) {
7906 *cb = *((MonoDelegate **)params [i]);
7908 *state = *((MonoObject **)params [i]);
7915 * mono_method_return_message_restore:
7917 * Restore results from message based processing back to arguments pointers
7920 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7922 MONO_REQ_GC_UNSAFE_MODE;
7926 MonoMethodSignature *sig = mono_method_signature (method);
7927 int i, j, type, size, out_len;
7929 if (out_args == NULL)
7931 out_len = mono_array_length (out_args);
7935 for (i = 0, j = 0; i < sig->param_count; i++) {
7936 MonoType *pt = sig->params [i];
7941 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7945 arg = (char *)mono_array_get (out_args, gpointer, j);
7948 g_assert (type != MONO_TYPE_VOID);
7950 if (MONO_TYPE_IS_REFERENCE (pt)) {
7951 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7954 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7955 size = mono_class_value_size (klass, NULL);
7956 if (klass->has_references)
7957 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7959 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7961 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7962 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7971 #ifndef DISABLE_REMOTING
7974 * mono_load_remote_field:
7975 * \param this pointer to an object
7976 * \param klass klass of the object containing \p field
7977 * \param field the field to load
7978 * \param res a storage to store the result
7979 * This method is called by the runtime on attempts to load fields of
7980 * transparent proxy objects. \p this points to such TP, \p klass is the class of
7981 * the object containing \p field. \p res is a storage location which can be
7982 * used to store the result.
7983 * \returns an address pointing to the value of field.
7986 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7989 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7990 mono_error_cleanup (&error);
7995 * mono_load_remote_field_checked:
7996 * \param this pointer to an object
7997 * \param klass klass of the object containing \p field
7998 * \param field the field to load
7999 * \param res a storage to store the result
8000 * \param error set on error
8001 * This method is called by the runtime on attempts to load fields of
8002 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8003 * the object containing \p field. \p res is a storage location which can be
8004 * used to store the result.
8005 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8008 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8010 MONO_REQ_GC_UNSAFE_MODE;
8012 static MonoMethod *getter = NULL;
8016 MonoDomain *domain = mono_domain_get ();
8017 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8018 MonoClass *field_class;
8019 MonoMethodMessage *msg;
8020 MonoArray *out_args;
8024 g_assert (mono_object_is_transparent_proxy (this_obj));
8025 g_assert (res != NULL);
8027 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8028 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8033 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8035 mono_error_set_not_supported (error, "Linked away.");
8040 field_class = mono_class_from_mono_type (field->type);
8042 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8043 return_val_if_nok (error, NULL);
8044 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8045 return_val_if_nok (error, NULL);
8046 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8047 return_val_if_nok (error, NULL);
8048 mono_message_init (domain, msg, rm, out_args, error);
8049 return_val_if_nok (error, NULL);
8051 full_name = mono_type_get_full_name (klass);
8052 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8053 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8056 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8057 return_val_if_nok (error, NULL);
8060 mono_error_set_exception_instance (error, (MonoException *)exc);
8064 if (mono_array_length (out_args) == 0)
8067 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8069 if (field_class->valuetype) {
8070 return ((char *)*res) + sizeof (MonoObject);
8076 * mono_load_remote_field_new:
8080 * Missing documentation.
8083 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8087 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8088 mono_error_cleanup (&error);
8093 * mono_load_remote_field_new_checked:
8094 * \param this pointer to an object
8095 * \param klass klass of the object containing \p field
8096 * \param field the field to load
8097 * \param error set on error.
8098 * This method is called by the runtime on attempts to load fields of
8099 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8100 * the object containing \p field.
8101 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8104 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8106 MONO_REQ_GC_UNSAFE_MODE;
8110 static MonoMethod *tp_load = NULL;
8112 g_assert (mono_object_is_transparent_proxy (this_obj));
8115 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8117 mono_error_set_not_supported (error, "Linked away.");
8122 /* MonoType *type = mono_class_get_type (klass); */
8128 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8132 * mono_store_remote_field:
8133 * \param this_obj pointer to an object
8134 * \param klass klass of the object containing \p field
8135 * \param field the field to load
8136 * \param val the value/object to store
8137 * This method is called by the runtime on attempts to store fields of
8138 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8139 * the object containing \p field. \p val is the new value to store in \p field.
8142 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8145 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8146 mono_error_cleanup (&error);
8150 * mono_store_remote_field_checked:
8151 * \param this_obj pointer to an object
8152 * \param klass klass of the object containing \p field
8153 * \param field the field to load
8154 * \param val the value/object to store
8155 * \param error set on error
8156 * This method is called by the runtime on attempts to store fields of
8157 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8158 * the object containing \p field. \p val is the new value to store in \p field.
8159 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8162 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8165 MONO_REQ_GC_UNSAFE_MODE;
8169 MonoDomain *domain = mono_domain_get ();
8170 MonoClass *field_class;
8173 g_assert (mono_object_is_transparent_proxy (this_obj));
8175 field_class = mono_class_from_mono_type (field->type);
8177 if (field_class->valuetype) {
8178 arg = mono_value_box_checked (domain, field_class, val, error);
8179 return_val_if_nok (error, FALSE);
8181 arg = *((MonoObject**)val);
8184 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8188 * mono_store_remote_field_new:
8193 * Missing documentation
8196 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8199 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8200 mono_error_cleanup (&error);
8204 * mono_store_remote_field_new_checked:
8210 * Missing documentation
8213 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8215 MONO_REQ_GC_UNSAFE_MODE;
8217 static MonoMethod *tp_store = NULL;
8221 g_assert (mono_object_is_transparent_proxy (this_obj));
8224 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8226 mono_error_set_not_supported (error, "Linked away.");
8236 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8237 return is_ok (error);
8242 * mono_create_ftnptr:
8244 * Given a function address, create a function descriptor for it.
8245 * This is only needed on some platforms.
8248 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8250 return callbacks.create_ftnptr (domain, addr);
8254 * mono_get_addr_from_ftnptr:
8256 * Given a pointer to a function descriptor, return the function address.
8257 * This is only needed on some platforms.
8260 mono_get_addr_from_ftnptr (gpointer descr)
8262 return callbacks.get_addr_from_ftnptr (descr);
8266 * mono_string_chars:
8267 * \param s a \c MonoString
8268 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8271 mono_string_chars (MonoString *s)
8273 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8279 * mono_string_length:
8280 * \param s MonoString
8281 * \returns the length in characters of the string
8284 mono_string_length (MonoString *s)
8286 MONO_REQ_GC_UNSAFE_MODE;
8292 * mono_string_handle_length:
8293 * \param s \c MonoString
8294 * \returns the length in characters of the string
8297 mono_string_handle_length (MonoStringHandle s)
8299 MONO_REQ_GC_UNSAFE_MODE;
8301 return MONO_HANDLE_GETVAL (s, length);
8306 * mono_array_length:
8307 * \param array a \c MonoArray*
8308 * \returns the total number of elements in the array. This works for
8309 * both vectors and multidimensional arrays.
8312 mono_array_length (MonoArray *array)
8314 MONO_REQ_GC_UNSAFE_MODE;
8316 return array->max_length;
8320 * mono_array_addr_with_size:
8321 * \param array a \c MonoArray*
8322 * \param size size of the array elements
8323 * \param idx index into the array
8324 * Use this function to obtain the address for the \p idx item on the
8325 * \p array containing elements of size \p size.
8327 * This method performs no bounds checking or type checking.
8328 * \returns the address of the \p idx element in the array.
8331 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8333 MONO_REQ_GC_UNSAFE_MODE;
8335 return ((char*)(array)->vector) + size * idx;
8340 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8342 MonoDomain *domain = mono_domain_get ();
8350 len = g_list_length (list);
8351 res = mono_array_new_checked (domain, eclass, len, error);
8352 return_val_if_nok (error, NULL);
8354 for (i = 0; list; list = list->next, i++)
8355 mono_array_set (res, gpointer, i, list->data);
8362 * The following section is purely to declare prototypes and
8363 * document the API, as these C files are processed by our
8369 * \param array array to alter
8370 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8371 * \param index index into the array
8372 * \param value value to set
8373 * Value Type version: This sets the \p index's element of the \p array
8374 * with elements of size sizeof(type) to the provided \p value.
8376 * This macro does not attempt to perform type checking or bounds checking.
8378 * Use this to set value types in a \c MonoArray.
8380 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8385 * mono_array_setref:
8386 * \param array array to alter
8387 * \param index index into the array
8388 * \param value value to set
8389 * Reference Type version: This sets the \p index's element of the
8390 * \p array with elements of size sizeof(type) to the provided \p value.
8392 * This macro does not attempt to perform type checking or bounds checking.
8394 * Use this to reference types in a \c MonoArray.
8396 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8402 * \param array array on which to operate on
8403 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8404 * \param index index into the array
8406 * Use this macro to retrieve the \p index element of an \p array and
8407 * extract the value assuming that the elements of the array match
8408 * the provided type value.
8410 * This method can be used with both arrays holding value types and
8411 * reference types. For reference types, the \p type parameter should
8412 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8414 * This macro does not attempt to perform type checking or bounds checking.
8416 * \returns The element at the \p index position in the \p array.
8418 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)