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 \c 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
3274 * mono_field_get_value (obj, int_field, &i);
3278 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3280 MONO_REQ_GC_UNSAFE_MODE;
3286 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3288 src = (char*)obj + field->offset;
3289 mono_copy_value (field->type, value, src, TRUE);
3293 * mono_field_get_value_object:
3294 * \param domain domain where the object will be created (if boxing)
3295 * \param field \c MonoClassField describing the field to fetch information from
3296 * \param obj The object instance for the field.
3297 * \returns a new \c MonoObject with the value from the given field. If the
3298 * field represents a value type, the value is boxed.
3301 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3304 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3305 mono_error_assert_ok (&error);
3310 * mono_field_get_value_object_checked:
3311 * \param domain domain where the object will be created (if boxing)
3312 * \param field \c MonoClassField describing the field to fetch information from
3313 * \param obj The object instance for the field.
3314 * \param error Set on error.
3315 * \returns a new \c MonoObject with the value from the given field. If the
3316 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3319 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3321 MONO_REQ_GC_UNSAFE_MODE;
3327 MonoVTable *vtable = NULL;
3329 gboolean is_static = FALSE;
3330 gboolean is_ref = FALSE;
3331 gboolean is_literal = FALSE;
3332 gboolean is_ptr = FALSE;
3333 MonoType *type = mono_field_get_type_checked (field, error);
3335 return_val_if_nok (error, NULL);
3337 switch (type->type) {
3338 case MONO_TYPE_STRING:
3339 case MONO_TYPE_OBJECT:
3340 case MONO_TYPE_CLASS:
3341 case MONO_TYPE_ARRAY:
3342 case MONO_TYPE_SZARRAY:
3347 case MONO_TYPE_BOOLEAN:
3350 case MONO_TYPE_CHAR:
3359 case MONO_TYPE_VALUETYPE:
3360 is_ref = type->byref;
3362 case MONO_TYPE_GENERICINST:
3363 is_ref = !mono_type_generic_inst_is_valuetype (type);
3369 g_error ("type 0x%x not handled in "
3370 "mono_field_get_value_object", type->type);
3374 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3377 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3381 vtable = mono_class_vtable_full (domain, field->parent, error);
3382 return_val_if_nok (error, NULL);
3384 if (!vtable->initialized) {
3385 mono_runtime_class_init_full (vtable, error);
3386 return_val_if_nok (error, NULL);
3395 get_default_field_value (domain, field, &o, error);
3396 return_val_if_nok (error, NULL);
3397 } else if (is_static) {
3398 mono_field_static_get_value_checked (vtable, field, &o, error);
3399 return_val_if_nok (error, NULL);
3401 mono_field_get_value (obj, field, &o);
3407 static MonoMethod *m;
3413 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3414 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3420 get_default_field_value (domain, field, v, error);
3421 return_val_if_nok (error, NULL);
3422 } else if (is_static) {
3423 mono_field_static_get_value_checked (vtable, field, v, error);
3424 return_val_if_nok (error, NULL);
3426 mono_field_get_value (obj, field, v);
3429 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3430 args [0] = ptr ? *ptr : NULL;
3431 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3432 return_val_if_nok (error, NULL);
3434 o = mono_runtime_invoke_checked (m, NULL, args, error);
3435 return_val_if_nok (error, NULL);
3440 /* boxed value type */
3441 klass = mono_class_from_mono_type (type);
3443 if (mono_class_is_nullable (klass))
3444 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3446 o = mono_object_new_checked (domain, klass, error);
3447 return_val_if_nok (error, NULL);
3448 v = ((gchar *) o) + sizeof (MonoObject);
3451 get_default_field_value (domain, field, v, error);
3452 return_val_if_nok (error, NULL);
3453 } else if (is_static) {
3454 mono_field_static_get_value_checked (vtable, field, v, error);
3455 return_val_if_nok (error, NULL);
3457 mono_field_get_value (obj, field, v);
3464 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3466 MONO_REQ_GC_UNSAFE_MODE;
3470 const char *p = blob;
3471 mono_metadata_decode_blob_size (p, &p);
3474 case MONO_TYPE_BOOLEAN:
3477 *(guint8 *) value = *p;
3479 case MONO_TYPE_CHAR:
3482 *(guint16*) value = read16 (p);
3486 *(guint32*) value = read32 (p);
3490 *(guint64*) value = read64 (p);
3493 readr4 (p, (float*) value);
3496 readr8 (p, (double*) value);
3498 case MONO_TYPE_STRING:
3499 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3501 case MONO_TYPE_CLASS:
3502 *(gpointer*) value = NULL;
3506 g_warning ("type 0x%02x should not be in constant table", type);
3512 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3514 MONO_REQ_GC_NEUTRAL_MODE;
3516 MonoTypeEnum def_type;
3521 data = mono_class_get_field_default_value (field, &def_type);
3522 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3526 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3528 MONO_REQ_GC_UNSAFE_MODE;
3534 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3536 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3537 get_default_field_value (vt->domain, field, value, error);
3541 if (field->offset == -1) {
3542 /* Special static */
3543 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3544 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3546 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3548 mono_copy_value (field->type, value, src, TRUE);
3552 * mono_field_static_get_value:
3553 * \param vt vtable to the object
3554 * \param field \c MonoClassField describing the field to fetch information from
3555 * \param value where the value is returned
3556 * Use this routine to get the value of the static field \p field value.
3558 * The pointer provided by value must be of the field type, for reference
3559 * types this is a \c MonoObject*, for value types its the actual pointer to
3567 * mono_field_static_get_value (vt, int_field, &i);
3571 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3573 MONO_REQ_GC_NEUTRAL_MODE;
3576 mono_field_static_get_value_checked (vt, field, value, &error);
3577 mono_error_cleanup (&error);
3581 * mono_field_static_get_value_checked:
3582 * \param vt vtable to the object
3583 * \param field \c MonoClassField describing the field to fetch information from
3584 * \param value where the value is returned
3585 * \param error set on error
3586 * Use this routine to get the value of the static field \p field value.
3588 * The pointer provided by value must be of the field type, for reference
3589 * types this is a \c MonoObject*, for value types its the actual pointer to
3594 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3595 * if (!is_ok (error)) { ... }
3597 * On failure sets \p error.
3600 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3602 MONO_REQ_GC_NEUTRAL_MODE;
3604 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3608 * mono_property_set_value:
3609 * \param prop MonoProperty to set
3610 * \param obj instance object on which to act
3611 * \param params parameters to pass to the propery
3612 * \param exc optional exception
3613 * Invokes the property's set method with the given arguments on the
3614 * object instance obj (or NULL for static properties).
3616 * You can pass NULL as the exc argument if you don't want to
3617 * catch exceptions, otherwise, \c *exc will be set to the exception
3618 * thrown, if any. if an exception is thrown, you can't use the
3619 * \c MonoObject* result from the function.
3622 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3624 MONO_REQ_GC_UNSAFE_MODE;
3627 do_runtime_invoke (prop->set, obj, params, exc, &error);
3628 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3629 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3631 mono_error_cleanup (&error);
3636 * mono_property_set_value_checked:
3637 * \param prop \c MonoProperty to set
3638 * \param obj instance object on which to act
3639 * \param params parameters to pass to the propery
3640 * \param error set on error
3641 * Invokes the property's set method with the given arguments on the
3642 * object instance \p obj (or NULL for static properties).
3643 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3644 * If an exception is thrown, it will be caught and returned via \p error.
3647 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3649 MONO_REQ_GC_UNSAFE_MODE;
3654 do_runtime_invoke (prop->set, obj, params, &exc, error);
3655 if (exc != NULL && is_ok (error))
3656 mono_error_set_exception_instance (error, (MonoException*)exc);
3657 return is_ok (error);
3661 * mono_property_get_value:
3662 * \param prop \c MonoProperty to fetch
3663 * \param obj instance object on which to act
3664 * \param params parameters to pass to the propery
3665 * \param exc optional exception
3666 * Invokes the property's \c get method with the given arguments on the
3667 * object instance \p obj (or NULL for static properties).
3669 * You can pass NULL as the \p exc argument if you don't want to
3670 * catch exceptions, otherwise, \c *exc will be set to the exception
3671 * thrown, if any. if an exception is thrown, you can't use the
3672 * \c MonoObject* result from the function.
3674 * \returns the value from invoking the \c get method on the property.
3677 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3679 MONO_REQ_GC_UNSAFE_MODE;
3682 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3683 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3684 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3686 mono_error_cleanup (&error); /* FIXME don't raise here */
3693 * mono_property_get_value_checked:
3694 * \param prop \c MonoProperty to fetch
3695 * \param obj instance object on which to act
3696 * \param params parameters to pass to the propery
3697 * \param error set on error
3698 * Invokes the property's \c get method with the given arguments on the
3699 * object instance obj (or NULL for static properties).
3701 * If an exception is thrown, you can't use the
3702 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3704 * \returns the value from invoking the get method on the property. On
3705 * failure returns NULL and sets \p error.
3708 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3710 MONO_REQ_GC_UNSAFE_MODE;
3713 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3714 if (exc != NULL && !is_ok (error))
3715 mono_error_set_exception_instance (error, (MonoException*) exc);
3723 * mono_nullable_init:
3724 * @buf: The nullable structure to initialize.
3725 * @value: the value to initialize from
3726 * @klass: the type for the object
3728 * Initialize the nullable structure pointed to by @buf from @value which
3729 * should be a boxed value type. The size of @buf should be able to hold
3730 * as much data as the @klass->instance_size (which is the number of bytes
3731 * that will be copies).
3733 * Since Nullables have variable structure, we can not define a C
3734 * structure for them.
3737 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3739 MONO_REQ_GC_UNSAFE_MODE;
3741 MonoClass *param_class = klass->cast_class;
3743 mono_class_setup_fields (klass);
3744 g_assert (klass->fields_inited);
3746 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3747 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3749 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3751 if (param_class->has_references)
3752 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3754 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3756 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3761 * mono_nullable_box:
3762 * \param buf The buffer representing the data to be boxed
3763 * \param klass the type to box it as.
3764 * \param error set on error
3766 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3767 * \p buf. On failure returns NULL and sets \p error.
3770 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3772 MONO_REQ_GC_UNSAFE_MODE;
3775 MonoClass *param_class = klass->cast_class;
3777 mono_class_setup_fields (klass);
3778 g_assert (klass->fields_inited);
3780 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3781 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3783 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3784 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3785 return_val_if_nok (error, NULL);
3786 if (param_class->has_references)
3787 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3789 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3797 * mono_get_delegate_invoke:
3798 * \param klass The delegate class
3799 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3802 mono_get_delegate_invoke (MonoClass *klass)
3804 MONO_REQ_GC_NEUTRAL_MODE;
3808 /* This is called at runtime, so avoid the slower search in metadata */
3809 mono_class_setup_methods (klass);
3810 if (mono_class_has_failure (klass))
3812 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3817 * mono_get_delegate_begin_invoke:
3818 * \param klass The delegate class
3819 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3822 mono_get_delegate_begin_invoke (MonoClass *klass)
3824 MONO_REQ_GC_NEUTRAL_MODE;
3828 /* This is called at runtime, so avoid the slower search in metadata */
3829 mono_class_setup_methods (klass);
3830 if (mono_class_has_failure (klass))
3832 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3837 * mono_get_delegate_end_invoke:
3838 * \param klass The delegate class
3839 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3842 mono_get_delegate_end_invoke (MonoClass *klass)
3844 MONO_REQ_GC_NEUTRAL_MODE;
3848 /* This is called at runtime, so avoid the slower search in metadata */
3849 mono_class_setup_methods (klass);
3850 if (mono_class_has_failure (klass))
3852 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3857 * mono_runtime_delegate_invoke:
3858 * \param delegate pointer to a delegate object.
3859 * \param params parameters for the delegate.
3860 * \param exc Pointer to the exception result.
3862 * Invokes the delegate method \p delegate with the parameters provided.
3864 * You can pass NULL as the \p exc argument if you don't want to
3865 * catch exceptions, otherwise, \c *exc will be set to the exception
3866 * thrown, if any. if an exception is thrown, you can't use the
3867 * \c MonoObject* result from the function.
3870 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3872 MONO_REQ_GC_UNSAFE_MODE;
3876 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3878 mono_error_cleanup (&error);
3881 if (!is_ok (&error))
3882 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3886 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3887 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3893 * mono_runtime_delegate_try_invoke:
3894 * \param delegate pointer to a delegate object.
3895 * \param params parameters for the delegate.
3896 * \param exc Pointer to the exception result.
3897 * \param error set on error
3898 * Invokes the delegate method \p delegate with the parameters provided.
3900 * You can pass NULL as the \p exc argument if you don't want to
3901 * catch exceptions, otherwise, \c *exc will be set to the exception
3902 * thrown, if any. On failure to execute, \p error will be set.
3903 * if an exception is thrown, you can't use the
3904 * \c MonoObject* result from the function.
3907 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3909 MONO_REQ_GC_UNSAFE_MODE;
3913 MonoClass *klass = delegate->vtable->klass;
3916 im = mono_get_delegate_invoke (klass);
3918 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3921 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3923 o = mono_runtime_invoke_checked (im, delegate, params, error);
3930 * mono_runtime_delegate_invoke_checked:
3931 * \param delegate pointer to a delegate object.
3932 * \param params parameters for the delegate.
3933 * \param error set on error
3934 * Invokes the delegate method \p delegate with the parameters provided.
3935 * On failure \p error will be set and you can't use the \c MonoObject*
3936 * result from the function.
3939 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3942 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3945 static char **main_args = NULL;
3946 static int num_main_args = 0;
3949 * mono_runtime_get_main_args:
3951 * Returns: a MonoArray with the arguments passed to the main program
3954 mono_runtime_get_main_args (void)
3956 MONO_REQ_GC_UNSAFE_MODE;
3958 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3959 mono_error_assert_ok (&error);
3964 * mono_runtime_get_main_args_checked:
3965 * \param error set on error
3966 * \returns a \c MonoArray with the arguments passed to the main
3967 * program. On failure returns NULL and sets \p error.
3970 mono_runtime_get_main_args_checked (MonoError *error)
3974 MonoDomain *domain = mono_domain_get ();
3978 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3979 return_val_if_nok (error, NULL);
3981 for (i = 0; i < num_main_args; ++i)
3982 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3988 free_main_args (void)
3990 MONO_REQ_GC_NEUTRAL_MODE;
3994 for (i = 0; i < num_main_args; ++i)
3995 g_free (main_args [i]);
4002 * mono_runtime_set_main_args:
4003 * \param argc number of arguments from the command line
4004 * \param argv array of strings from the command line
4005 * Set the command line arguments from an embedding application that doesn't otherwise call
4006 * \c mono_runtime_run_main.
4009 mono_runtime_set_main_args (int argc, char* argv[])
4011 MONO_REQ_GC_NEUTRAL_MODE;
4016 main_args = g_new0 (char*, argc);
4017 num_main_args = argc;
4019 for (i = 0; i < argc; ++i) {
4022 utf8_arg = mono_utf8_from_external (argv[i]);
4023 if (utf8_arg == NULL) {
4024 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4025 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4029 main_args [i] = utf8_arg;
4036 * Prepare an array of arguments in order to execute a standard Main()
4037 * method (argc/argv contains the executable name). This method also
4038 * sets the command line argument value needed by System.Environment.
4042 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4044 MONO_REQ_GC_UNSAFE_MODE;
4048 MonoArray *args = NULL;
4049 MonoDomain *domain = mono_domain_get ();
4050 gchar *utf8_fullpath;
4051 MonoMethodSignature *sig;
4053 g_assert (method != NULL);
4055 mono_thread_set_main (mono_thread_current ());
4057 main_args = g_new0 (char*, argc);
4058 num_main_args = argc;
4060 if (!g_path_is_absolute (argv [0])) {
4061 gchar *basename = g_path_get_basename (argv [0]);
4062 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4066 utf8_fullpath = mono_utf8_from_external (fullpath);
4067 if(utf8_fullpath == NULL) {
4068 /* Printing the arg text will cause glib to
4069 * whinge about "Invalid UTF-8", but at least
4070 * its relevant, and shows the problem text
4073 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4074 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4081 utf8_fullpath = mono_utf8_from_external (argv[0]);
4082 if(utf8_fullpath == NULL) {
4083 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4084 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4089 main_args [0] = utf8_fullpath;
4091 for (i = 1; i < argc; ++i) {
4094 utf8_arg=mono_utf8_from_external (argv[i]);
4095 if(utf8_arg==NULL) {
4096 /* Ditto the comment about Invalid UTF-8 here */
4097 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4098 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4102 main_args [i] = utf8_arg;
4107 sig = mono_method_signature (method);
4109 g_print ("Unable to load Main method.\n");
4113 if (sig->param_count) {
4114 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4115 mono_error_assert_ok (&error);
4116 for (i = 0; i < argc; ++i) {
4117 /* The encodings should all work, given that
4118 * we've checked all these args for the
4121 gchar *str = mono_utf8_from_external (argv [i]);
4122 MonoString *arg = mono_string_new (domain, str);
4123 mono_array_setref (args, i, arg);
4127 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4128 mono_error_assert_ok (&error);
4131 mono_assembly_set_main (method->klass->image->assembly);
4137 * mono_runtime_run_main:
4138 * \param method the method to start the application with (usually \c Main)
4139 * \param argc number of arguments from the command line
4140 * \param argv array of strings from the command line
4141 * \param exc excetption results
4142 * Execute a standard \c Main method (\p argc / \p argv contains the
4143 * executable name). This method also sets the command line argument value
4144 * needed by \c System.Environment.
4147 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4150 MONO_REQ_GC_UNSAFE_MODE;
4153 MonoArray *args = prepare_run_main (method, argc, argv);
4156 res = mono_runtime_try_exec_main (method, args, exc);
4158 res = mono_runtime_exec_main_checked (method, args, &error);
4159 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4165 * mono_runtime_run_main_checked:
4166 * \param method the method to start the application with (usually \c Main)
4167 * \param argc number of arguments from the command line
4168 * \param argv array of strings from the command line
4169 * \param error set on error
4171 * Execute a standard \c Main method (\p argc / \p argv contains the
4172 * executable name). This method also sets the command line argument value
4173 * needed by \c System.Environment. On failure sets \p error.
4176 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4180 MonoArray *args = prepare_run_main (method, argc, argv);
4181 return mono_runtime_exec_main_checked (method, args, error);
4185 * mono_runtime_try_run_main:
4186 * \param method the method to start the application with (usually \c Main)
4187 * \param argc number of arguments from the command line
4188 * \param argv array of strings from the command line
4189 * \param exc set if \c Main throws an exception
4190 * \param error set if \c Main can't be executed
4191 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4192 * name). This method also sets the command line argument value needed
4193 * by \c System.Environment. On failure sets \p error if Main can't be
4194 * executed or \p exc if it threw an exception.
4197 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4201 MonoArray *args = prepare_run_main (method, argc, argv);
4202 return mono_runtime_try_exec_main (method, args, exc);
4207 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4209 static MonoMethod *serialize_method;
4215 if (!serialize_method) {
4216 MonoClass *klass = mono_class_get_remoting_services_class ();
4217 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4220 if (!serialize_method) {
4225 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4230 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4231 if (*exc == NULL && !mono_error_ok (&error))
4232 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4234 mono_error_cleanup (&error);
4243 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4245 MONO_REQ_GC_UNSAFE_MODE;
4247 static MonoMethod *deserialize_method;
4253 if (!deserialize_method) {
4254 MonoClass *klass = mono_class_get_remoting_services_class ();
4255 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4257 if (!deserialize_method) {
4265 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4266 if (*exc == NULL && !mono_error_ok (&error))
4267 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4269 mono_error_cleanup (&error);
4277 #ifndef DISABLE_REMOTING
4279 make_transparent_proxy (MonoObject *obj, MonoError *error)
4281 MONO_REQ_GC_UNSAFE_MODE;
4283 static MonoMethod *get_proxy_method;
4285 MonoDomain *domain = mono_domain_get ();
4286 MonoRealProxy *real_proxy;
4287 MonoReflectionType *reflection_type;
4288 MonoTransparentProxy *transparent_proxy;
4292 if (!get_proxy_method)
4293 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4295 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4297 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4298 return_val_if_nok (error, NULL);
4299 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4300 return_val_if_nok (error, NULL);
4302 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4303 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4305 MonoObject *exc = NULL;
4307 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4308 if (exc != NULL && is_ok (error))
4309 mono_error_set_exception_instance (error, (MonoException*)exc);
4311 return (MonoObject*) transparent_proxy;
4313 #endif /* DISABLE_REMOTING */
4316 * mono_object_xdomain_representation
4317 * \param obj an object
4318 * \param target_domain a domain
4319 * \param error set on error.
4320 * Creates a representation of obj in the domain \p target_domain. This
4321 * is either a copy of \p obj arrived through via serialization and
4322 * deserialization or a proxy, depending on whether the object is
4323 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4324 * If the object cannot be represented in \p target_domain, NULL is
4325 * returned and \p error is set appropriately.
4328 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4330 MONO_REQ_GC_UNSAFE_MODE;
4333 MonoObject *deserialized = NULL;
4335 #ifndef DISABLE_REMOTING
4336 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4337 deserialized = make_transparent_proxy (obj, error);
4342 gboolean failure = FALSE;
4343 MonoDomain *domain = mono_domain_get ();
4344 MonoObject *serialized;
4345 MonoObject *exc = NULL;
4347 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4348 serialized = serialize_object (obj, &failure, &exc);
4349 mono_domain_set_internal_with_options (target_domain, FALSE);
4351 deserialized = deserialize_object (serialized, &failure, &exc);
4352 if (domain != target_domain)
4353 mono_domain_set_internal_with_options (domain, FALSE);
4355 mono_error_set_exception_instance (error, (MonoException*)exc);
4358 return deserialized;
4361 /* Used in call_unhandled_exception_delegate */
4363 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4365 MONO_REQ_GC_UNSAFE_MODE;
4370 MonoMethod *method = NULL;
4371 MonoBoolean is_terminating = TRUE;
4374 klass = mono_class_get_unhandled_exception_event_args_class ();
4375 mono_class_init (klass);
4377 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4378 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4382 args [1] = &is_terminating;
4384 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4385 return_val_if_nok (error, NULL);
4387 mono_runtime_invoke_checked (method, obj, args, error);
4388 return_val_if_nok (error, NULL);
4393 /* Used in mono_unhandled_exception */
4395 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4396 MONO_REQ_GC_UNSAFE_MODE;
4399 MonoObject *e = NULL;
4401 MonoDomain *current_domain = mono_domain_get ();
4403 if (domain != current_domain)
4404 mono_domain_set_internal_with_options (domain, FALSE);
4406 g_assert (domain == mono_object_domain (domain->domain));
4408 if (mono_object_domain (exc) != domain) {
4410 exc = mono_object_xdomain_representation (exc, domain, &error);
4412 if (!is_ok (&error)) {
4413 MonoError inner_error;
4414 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4415 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4416 mono_error_assert_ok (&inner_error);
4418 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4419 "System.Runtime.Serialization", "SerializationException",
4420 "Could not serialize unhandled exception.");
4424 g_assert (mono_object_domain (exc) == domain);
4426 pa [0] = domain->domain;
4427 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4428 mono_error_assert_ok (&error);
4429 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4430 if (!is_ok (&error)) {
4432 e = (MonoObject*)mono_error_convert_to_exception (&error);
4434 mono_error_cleanup (&error);
4437 if (domain != current_domain)
4438 mono_domain_set_internal_with_options (current_domain, FALSE);
4441 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4442 if (!mono_error_ok (&error)) {
4443 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4444 mono_error_cleanup (&error);
4446 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4452 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4455 * mono_runtime_unhandled_exception_policy_set:
4456 * \param policy the new policy
4457 * This is a VM internal routine.
4458 * Sets the runtime policy for handling unhandled exceptions.
4461 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4462 runtime_unhandled_exception_policy = policy;
4466 * mono_runtime_unhandled_exception_policy_get:
4468 * This is a VM internal routine.
4470 * Gets the runtime policy for handling unhandled exceptions.
4472 MonoRuntimeUnhandledExceptionPolicy
4473 mono_runtime_unhandled_exception_policy_get (void) {
4474 return runtime_unhandled_exception_policy;
4478 * mono_unhandled_exception:
4479 * \param exc exception thrown
4480 * This is a VM internal routine.
4482 * We call this function when we detect an unhandled exception
4483 * in the default domain.
4485 * It invokes the \c UnhandledException event in \c AppDomain or prints
4486 * a warning to the console
4489 mono_unhandled_exception (MonoObject *exc)
4491 MONO_REQ_GC_UNSAFE_MODE;
4494 MonoClassField *field;
4495 MonoDomain *current_domain, *root_domain;
4496 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4498 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4501 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4504 current_domain = mono_domain_get ();
4505 root_domain = mono_get_root_domain ();
4507 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4508 mono_error_assert_ok (&error);
4509 if (current_domain != root_domain) {
4510 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4511 mono_error_assert_ok (&error);
4514 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4515 mono_print_unhandled_exception (exc);
4517 /* unhandled exception callbacks must not be aborted */
4518 mono_threads_begin_abort_protected_block ();
4519 if (root_appdomain_delegate)
4520 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4521 if (current_appdomain_delegate)
4522 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4523 mono_threads_end_abort_protected_block ();
4526 /* set exitcode only if we will abort the process */
4527 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4528 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4530 mono_environment_exitcode_set (1);
4535 * mono_runtime_exec_managed_code:
4536 * \param domain Application domain
4537 * \param main_func function to invoke from the execution thread
4538 * \param main_args parameter to the main_func
4539 * Launch a new thread to execute a function
4541 * \p main_func is called back from the thread with main_args as the
4542 * parameter. The callback function is expected to start \c Main
4543 * eventually. This function then waits for all managed threads to
4545 * It is not necessary anymore to execute managed code in a subthread,
4546 * so this function should not be used anymore by default: just
4547 * execute the code and then call mono_thread_manage().
4550 mono_runtime_exec_managed_code (MonoDomain *domain,
4551 MonoMainThreadFunc main_func,
4555 mono_thread_create_checked (domain, main_func, main_args, &error);
4556 mono_error_assert_ok (&error);
4558 mono_thread_manage ();
4562 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4564 MonoInternalThread* thread = mono_thread_internal_current ();
4565 MonoCustomAttrInfo* cinfo;
4566 gboolean has_stathread_attribute;
4568 if (!domain->entry_assembly) {
4570 MonoAssembly *assembly;
4572 assembly = method->klass->image->assembly;
4573 domain->entry_assembly = assembly;
4574 /* Domains created from another domain already have application_base and configuration_file set */
4575 if (domain->setup->application_base == NULL) {
4576 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4579 if (domain->setup->configuration_file == NULL) {
4580 str = g_strconcat (assembly->image->name, ".config", NULL);
4581 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4583 mono_domain_set_options_from_config (domain);
4587 MonoError cattr_error;
4588 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4589 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4591 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4593 mono_custom_attrs_free (cinfo);
4595 has_stathread_attribute = FALSE;
4597 if (has_stathread_attribute) {
4598 thread->apartment_state = ThreadApartmentState_STA;
4600 thread->apartment_state = ThreadApartmentState_MTA;
4602 mono_thread_init_apartment_state ();
4607 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4609 MONO_REQ_GC_UNSAFE_MODE;
4619 /* FIXME: check signature of method */
4620 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4622 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4624 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4627 mono_environment_exitcode_set (rval);
4629 mono_runtime_invoke_checked (method, NULL, pa, error);
4641 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4643 MONO_REQ_GC_UNSAFE_MODE;
4653 /* FIXME: check signature of method */
4654 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4655 MonoError inner_error;
4657 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4658 if (*exc == NULL && !mono_error_ok (&inner_error))
4659 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4661 mono_error_cleanup (&inner_error);
4664 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4668 mono_environment_exitcode_set (rval);
4670 MonoError inner_error;
4671 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4672 if (*exc == NULL && !mono_error_ok (&inner_error))
4673 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4675 mono_error_cleanup (&inner_error);
4680 /* If the return type of Main is void, only
4681 * set the exitcode if an exception was thrown
4682 * (we don't want to blow away an
4683 * explicitly-set exit code)
4686 mono_environment_exitcode_set (rval);
4694 * Execute a standard Main() method (args doesn't contain the
4698 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4701 prepare_thread_to_exec_main (mono_object_domain (args), method);
4703 int rval = do_try_exec_main (method, args, exc);
4706 int rval = do_exec_main_checked (method, args, &error);
4707 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4713 * Execute a standard Main() method (args doesn't contain the
4716 * On failure sets @error
4719 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4722 prepare_thread_to_exec_main (mono_object_domain (args), method);
4723 return do_exec_main_checked (method, args, error);
4727 * Execute a standard Main() method (args doesn't contain the
4730 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4733 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4735 prepare_thread_to_exec_main (mono_object_domain (args), method);
4736 return do_try_exec_main (method, args, exc);
4741 /** invoke_array_extract_argument:
4742 * @params: array of arguments to the method.
4743 * @i: the index of the argument to extract.
4744 * @t: ith type from the method signature.
4745 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4746 * @error: set on error.
4748 * Given an array of method arguments, return the ith one using the corresponding type
4749 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4751 * On failure sets @error and returns NULL.
4754 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4756 MonoType *t_orig = t;
4757 gpointer result = NULL;
4763 case MONO_TYPE_BOOLEAN:
4766 case MONO_TYPE_CHAR:
4775 case MONO_TYPE_VALUETYPE:
4776 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4777 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4778 result = mono_array_get (params, MonoObject*, i);
4780 *has_byref_nullables = TRUE;
4782 /* MS seems to create the objects if a null is passed in */
4783 gboolean was_null = FALSE;
4784 if (!mono_array_get (params, MonoObject*, i)) {
4785 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4786 return_val_if_nok (error, NULL);
4787 mono_array_setref (params, i, o);
4793 * We can't pass the unboxed vtype byref to the callee, since
4794 * that would mean the callee would be able to modify boxed
4795 * primitive types. So we (and MS) make a copy of the boxed
4796 * object, pass that to the callee, and replace the original
4797 * boxed object in the arg array with the copy.
4799 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4800 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4801 return_val_if_nok (error, NULL);
4802 mono_array_setref (params, i, copy);
4805 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4806 if (!t->byref && was_null)
4807 mono_array_setref (params, i, NULL);
4810 case MONO_TYPE_STRING:
4811 case MONO_TYPE_OBJECT:
4812 case MONO_TYPE_CLASS:
4813 case MONO_TYPE_ARRAY:
4814 case MONO_TYPE_SZARRAY:
4816 result = mono_array_addr (params, MonoObject*, i);
4817 // FIXME: I need to check this code path
4819 result = mono_array_get (params, MonoObject*, i);
4821 case MONO_TYPE_GENERICINST:
4823 t = &t->data.generic_class->container_class->this_arg;
4825 t = &t->data.generic_class->container_class->byval_arg;
4827 case MONO_TYPE_PTR: {
4830 /* The argument should be an IntPtr */
4831 arg = mono_array_get (params, MonoObject*, i);
4835 g_assert (arg->vtable->klass == mono_defaults.int_class);
4836 result = ((MonoIntPtr*)arg)->m_value;
4841 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4846 * mono_runtime_invoke_array:
4847 * \param method method to invoke
4848 * \param obj object instance
4849 * \param params arguments to the method
4850 * \param exc exception information.
4851 * Invokes the method represented by \p method on the object \p obj.
4853 * \p obj is the \c this pointer, it should be NULL for static
4854 * methods, a \c MonoObject* for object instances and a pointer to
4855 * the value type for value types.
4857 * The \p params array contains the arguments to the method with the
4858 * same convention: \c MonoObject* pointers for object instances and
4859 * pointers to the value type otherwise. The \c _invoke_array
4860 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4861 * in this case the value types are boxed inside the
4862 * respective reference representation.
4864 * From unmanaged code you'll usually use the
4865 * mono_runtime_invoke_checked() variant.
4867 * Note that this function doesn't handle virtual methods for
4868 * you, it will exec the exact method you pass: we still need to
4869 * expose a function to lookup the derived class implementation
4870 * of a virtual method (there are examples of this in the code,
4873 * You can pass NULL as the \p exc argument if you don't want to
4874 * catch exceptions, otherwise, \c *exc will be set to the exception
4875 * thrown, if any. if an exception is thrown, you can't use the
4876 * \c MonoObject* result from the function.
4878 * If the method returns a value type, it is boxed in an object
4882 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4887 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4889 mono_error_cleanup (&error);
4892 if (!is_ok (&error))
4893 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4897 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4898 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4904 * mono_runtime_invoke_array_checked:
4905 * \param method method to invoke
4906 * \param obj object instance
4907 * \param params arguments to the method
4908 * \param error set on failure.
4909 * Invokes the method represented by \p method on the object \p obj.
4911 * \p obj is the \c this pointer, it should be NULL for static
4912 * methods, a \c MonoObject* for object instances and a pointer to
4913 * the value type for value types.
4915 * The \p params array contains the arguments to the method with the
4916 * same convention: \c MonoObject* pointers for object instances and
4917 * pointers to the value type otherwise. The \c _invoke_array
4918 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
4919 * in this case the value types are boxed inside the
4920 * respective reference representation.
4922 * From unmanaged code you'll usually use the
4923 * mono_runtime_invoke_checked() variant.
4925 * Note that this function doesn't handle virtual methods for
4926 * you, it will exec the exact method you pass: we still need to
4927 * expose a function to lookup the derived class implementation
4928 * of a virtual method (there are examples of this in the code,
4931 * On failure or exception, \p error will be set. In that case, you
4932 * can't use the \c MonoObject* result from the function.
4934 * If the method returns a value type, it is boxed in an object
4938 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4942 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4946 * mono_runtime_try_invoke_array:
4947 * \param method method to invoke
4948 * \param obj object instance
4949 * \param params arguments to the method
4950 * \param exc exception information.
4951 * \param error set on failure.
4952 * Invokes the method represented by \p method on the object \p obj.
4954 * \p obj is the \c this pointer, it should be NULL for static
4955 * methods, a \c MonoObject* for object instances and a pointer to
4956 * the value type for value types.
4958 * The \p params array contains the arguments to the method with the
4959 * same convention: \c MonoObject* pointers for object instances and
4960 * pointers to the value type otherwise. The \c _invoke_array
4961 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4962 * in this case the value types are boxed inside the
4963 * respective reference representation.
4965 * From unmanaged code you'll usually use the
4966 * mono_runtime_invoke_checked() variant.
4968 * Note that this function doesn't handle virtual methods for
4969 * you, it will exec the exact method you pass: we still need to
4970 * expose a function to lookup the derived class implementation
4971 * of a virtual method (there are examples of this in the code,
4974 * You can pass NULL as the \p exc argument if you don't want to catch
4975 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
4976 * any. On other failures, \p error will be set. If an exception is
4977 * thrown or there's an error, you can't use the \c MonoObject* result
4978 * from the function.
4980 * If the method returns a value type, it is boxed in an object
4984 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4985 MonoObject **exc, MonoError *error)
4987 MONO_REQ_GC_UNSAFE_MODE;
4991 MonoMethodSignature *sig = mono_method_signature (method);
4992 gpointer *pa = NULL;
4995 gboolean has_byref_nullables = FALSE;
4997 if (NULL != params) {
4998 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4999 for (i = 0; i < mono_array_length (params); i++) {
5000 MonoType *t = sig->params [i];
5001 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5002 return_val_if_nok (error, NULL);
5006 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5009 if (mono_class_is_nullable (method->klass)) {
5010 /* Need to create a boxed vtype instead */
5016 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5021 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5022 mono_error_assert_ok (error);
5023 g_assert (obj); /*maybe we should raise a TLE instead?*/
5024 #ifndef DISABLE_REMOTING
5025 if (mono_object_is_transparent_proxy (obj)) {
5026 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5029 if (method->klass->valuetype)
5030 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5033 } else if (method->klass->valuetype) {
5034 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5035 return_val_if_nok (error, NULL);
5039 mono_runtime_try_invoke (method, o, pa, exc, error);
5041 mono_runtime_invoke_checked (method, o, pa, error);
5044 return (MonoObject *)obj;
5046 if (mono_class_is_nullable (method->klass)) {
5047 MonoObject *nullable;
5049 /* Convert the unboxed vtype into a Nullable structure */
5050 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5051 return_val_if_nok (error, NULL);
5053 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5054 return_val_if_nok (error, NULL);
5055 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5056 obj = mono_object_unbox (nullable);
5059 /* obj must be already unboxed if needed */
5061 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5063 res = mono_runtime_invoke_checked (method, obj, pa, error);
5065 return_val_if_nok (error, NULL);
5067 if (sig->ret->type == MONO_TYPE_PTR) {
5068 MonoClass *pointer_class;
5069 static MonoMethod *box_method;
5071 MonoObject *box_exc;
5074 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5075 * convert it to a Pointer object.
5077 pointer_class = mono_class_get_pointer_class ();
5079 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5081 g_assert (res->vtable->klass == mono_defaults.int_class);
5082 box_args [0] = ((MonoIntPtr*)res)->m_value;
5083 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5084 return_val_if_nok (error, NULL);
5086 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5087 g_assert (box_exc == NULL);
5088 mono_error_assert_ok (error);
5091 if (has_byref_nullables) {
5093 * The runtime invoke wrapper already converted byref nullables back,
5094 * and stored them in pa, we just need to copy them back to the
5097 for (i = 0; i < mono_array_length (params); i++) {
5098 MonoType *t = sig->params [i];
5100 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5101 mono_array_setref (params, i, pa [i]);
5111 * \param klass the class of the object that we want to create
5112 * \returns a newly created object whose definition is
5113 * looked up using \p klass. This will not invoke any constructors,
5114 * so the consumer of this routine has to invoke any constructors on
5115 * its own to initialize the object.
5117 * It returns NULL on failure.
5120 mono_object_new (MonoDomain *domain, MonoClass *klass)
5122 MONO_REQ_GC_UNSAFE_MODE;
5126 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5128 mono_error_cleanup (&error);
5133 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5135 MONO_REQ_GC_UNSAFE_MODE;
5139 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5141 mono_error_set_pending_exception (&error);
5146 * mono_object_new_checked:
5147 * \param klass the class of the object that we want to create
5148 * \param error set on error
5149 * \returns a newly created object whose definition is
5150 * looked up using \p klass. This will not invoke any constructors,
5151 * so the consumer of this routine has to invoke any constructors on
5152 * its own to initialize the object.
5154 * It returns NULL on failure and sets \p error.
5157 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5159 MONO_REQ_GC_UNSAFE_MODE;
5163 vtable = mono_class_vtable (domain, klass);
5164 g_assert (vtable); /* FIXME don't swallow the error */
5166 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5171 * mono_object_new_pinned:
5173 * Same as mono_object_new, but the returned object will be pinned.
5174 * For SGEN, these objects will only be freed at appdomain unload.
5177 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5179 MONO_REQ_GC_UNSAFE_MODE;
5185 vtable = mono_class_vtable (domain, klass);
5186 g_assert (vtable); /* FIXME don't swallow the error */
5188 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5190 if (G_UNLIKELY (!o))
5191 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5192 else if (G_UNLIKELY (vtable->klass->has_finalize))
5193 mono_object_register_finalizer (o);
5199 * mono_object_new_specific:
5200 * \param vtable the vtable of the object that we want to create
5201 * \returns A newly created object with class and domain specified
5205 mono_object_new_specific (MonoVTable *vtable)
5208 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5209 mono_error_cleanup (&error);
5215 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5217 MONO_REQ_GC_UNSAFE_MODE;
5223 /* check for is_com_object for COM Interop */
5224 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5227 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5230 MonoClass *klass = mono_class_get_activation_services_class ();
5233 mono_class_init (klass);
5235 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5237 mono_error_set_not_supported (error, "Linked away.");
5240 vtable->domain->create_proxy_for_type_method = im;
5243 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5244 if (!mono_error_ok (error))
5247 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5248 if (!mono_error_ok (error))
5255 return mono_object_new_alloc_specific_checked (vtable, error);
5259 ves_icall_object_new_specific (MonoVTable *vtable)
5262 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5263 mono_error_set_pending_exception (&error);
5269 * mono_object_new_alloc_specific:
5270 * \param vtable virtual table for the object.
5271 * This function allocates a new \c MonoObject with the type derived
5272 * from the \p vtable information. If the class of this object has a
5273 * finalizer, then the object will be tracked for finalization.
5275 * This method might raise an exception on errors. Use the
5276 * \c mono_object_new_fast_checked method if you want to manually raise
5279 * \returns the allocated object.
5282 mono_object_new_alloc_specific (MonoVTable *vtable)
5285 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5286 mono_error_cleanup (&error);
5292 * mono_object_new_alloc_specific_checked:
5293 * \param vtable virtual table for the object.
5294 * \param error holds the error return value.
5296 * This function allocates a new \c MonoObject with the type derived
5297 * from the \p vtable information. If the class of this object has a
5298 * finalizer, then the object will be tracked for finalization.
5300 * If there is not enough memory, the \p error parameter will be set
5301 * and will contain a user-visible message with the amount of bytes
5302 * that were requested.
5304 * \returns the allocated object, or NULL if there is not enough memory
5307 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5309 MONO_REQ_GC_UNSAFE_MODE;
5315 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5317 if (G_UNLIKELY (!o))
5318 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5319 else if (G_UNLIKELY (vtable->klass->has_finalize))
5320 mono_object_register_finalizer (o);
5326 * mono_object_new_fast:
5327 * \param vtable virtual table for the object.
5329 * This function allocates a new \c MonoObject with the type derived
5330 * from the \p vtable information. The returned object is not tracked
5331 * for finalization. If your object implements a finalizer, you should
5332 * use \c mono_object_new_alloc_specific instead.
5334 * This method might raise an exception on errors. Use the
5335 * \c mono_object_new_fast_checked method if you want to manually raise
5338 * \returns the allocated object.
5341 mono_object_new_fast (MonoVTable *vtable)
5344 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5345 mono_error_cleanup (&error);
5351 * mono_object_new_fast_checked:
5352 * \param vtable virtual table for the object.
5353 * \param error holds the error return value.
5355 * This function allocates a new \c MonoObject with the type derived
5356 * from the \p vtable information. The returned object is not tracked
5357 * for finalization. If your object implements a finalizer, you should
5358 * use \c mono_object_new_alloc_specific_checked instead.
5360 * If there is not enough memory, the \p error parameter will be set
5361 * and will contain a user-visible message with the amount of bytes
5362 * that were requested.
5364 * \returns the allocated object, or NULL if there is not enough memory
5367 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5369 MONO_REQ_GC_UNSAFE_MODE;
5375 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5377 if (G_UNLIKELY (!o))
5378 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5384 ves_icall_object_new_fast (MonoVTable *vtable)
5387 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5388 mono_error_set_pending_exception (&error);
5394 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5396 MONO_REQ_GC_UNSAFE_MODE;
5402 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5404 if (G_UNLIKELY (!o))
5405 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5406 else if (G_UNLIKELY (vtable->klass->has_finalize))
5407 mono_object_register_finalizer (o);
5413 * mono_class_get_allocation_ftn:
5414 * \param vtable vtable
5415 * \param for_box the object will be used for boxing
5416 * \param pass_size_in_words Unused
5417 * \returns the allocation function appropriate for the given class.
5420 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5422 MONO_REQ_GC_NEUTRAL_MODE;
5424 *pass_size_in_words = FALSE;
5426 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5427 return ves_icall_object_new_specific;
5429 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5431 return ves_icall_object_new_fast;
5434 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5435 * of the overhead of parameter passing.
5438 *pass_size_in_words = TRUE;
5439 #ifdef GC_REDIRECT_TO_LOCAL
5440 return GC_local_gcj_fast_malloc;
5442 return GC_gcj_fast_malloc;
5447 return ves_icall_object_new_specific;
5451 * mono_object_new_from_token:
5452 * \param image Context where the type_token is hosted
5453 * \param token a token of the type that we want to create
5454 * \returns A newly created object whose definition is
5455 * looked up using \p token in the \p image image
5458 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5460 MONO_REQ_GC_UNSAFE_MODE;
5466 klass = mono_class_get_checked (image, token, &error);
5467 mono_error_assert_ok (&error);
5469 result = mono_object_new_checked (domain, klass, &error);
5471 mono_error_cleanup (&error);
5478 * mono_object_clone:
5479 * \param obj the object to clone
5480 * \returns A newly created object who is a shallow copy of \p obj
5483 mono_object_clone (MonoObject *obj)
5486 MonoObject *o = mono_object_clone_checked (obj, &error);
5487 mono_error_cleanup (&error);
5493 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5495 MONO_REQ_GC_UNSAFE_MODE;
5502 size = obj->vtable->klass->instance_size;
5504 if (obj->vtable->klass->rank)
5505 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5507 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5509 if (G_UNLIKELY (!o)) {
5510 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5514 /* If the object doesn't contain references this will do a simple memmove. */
5515 mono_gc_wbarrier_object_copy (o, obj);
5517 if (obj->vtable->klass->has_finalize)
5518 mono_object_register_finalizer (o);
5523 * mono_array_full_copy:
5524 * \param src source array to copy
5525 * \param dest destination array
5526 * Copies the content of one array to another with exactly the same type and size.
5529 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5531 MONO_REQ_GC_UNSAFE_MODE;
5534 MonoClass *klass = src->obj.vtable->klass;
5536 g_assert (klass == dest->obj.vtable->klass);
5538 size = mono_array_length (src);
5539 g_assert (size == mono_array_length (dest));
5540 size *= mono_array_element_size (klass);
5542 array_full_copy_unchecked_size (src, dest, klass, size);
5546 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5549 if (klass->element_class->valuetype) {
5550 if (klass->element_class->has_references)
5551 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5553 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5555 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5558 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5563 * mono_array_clone_in_domain:
5564 * \param domain the domain in which the array will be cloned into
5565 * \param array the array to clone
5566 * \param error set on error
5567 * This routine returns a copy of the array that is hosted on the
5568 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5571 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5573 MONO_REQ_GC_UNSAFE_MODE;
5575 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5577 MonoClass *klass = mono_handle_class (array_handle);
5581 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5582 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5584 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5586 if (array_bounds == NULL) {
5587 size = mono_array_handle_length (array_handle);
5588 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5591 size *= mono_array_element_size (klass);
5593 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5594 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5595 size = mono_array_element_size (klass);
5596 for (int i = 0; i < klass->rank; ++i) {
5597 sizes [i] = array_bounds [i].length;
5598 size *= array_bounds [i].length;
5599 lower_bounds [i] = array_bounds [i].lower_bound;
5601 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5606 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5607 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5608 mono_gchandle_free (dst_handle);
5610 MONO_HANDLE_ASSIGN (result, o);
5613 mono_gchandle_free (src_handle);
5619 * \param array the array to clone
5620 * \returns A newly created array who is a shallow copy of \p array
5623 mono_array_clone (MonoArray *array)
5625 MONO_REQ_GC_UNSAFE_MODE;
5628 MonoArray *result = mono_array_clone_checked (array, &error);
5629 mono_error_cleanup (&error);
5634 * mono_array_clone_checked:
5635 * \param array the array to clone
5636 * \param error set on error
5637 * \returns A newly created array who is a shallow copy of \p array. On
5638 * failure returns NULL and sets \p error.
5641 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5643 MONO_REQ_GC_UNSAFE_MODE;
5644 HANDLE_FUNCTION_ENTER ();
5645 /* FIXME: callers of mono_array_clone_checked should use handles */
5647 MONO_HANDLE_DCL (MonoArray, array);
5648 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5649 HANDLE_FUNCTION_RETURN_OBJ (result);
5652 /* helper macros to check for overflow when calculating the size of arrays */
5653 #ifdef MONO_BIG_ARRAYS
5654 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5655 #define MYGUINT_MAX MYGUINT64_MAX
5656 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5657 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5658 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5659 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5660 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5662 #define MYGUINT32_MAX 4294967295U
5663 #define MYGUINT_MAX MYGUINT32_MAX
5664 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5665 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5666 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5667 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5668 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5672 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5674 MONO_REQ_GC_NEUTRAL_MODE;
5678 byte_len = mono_array_element_size (klass);
5679 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5682 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5684 byte_len += MONO_SIZEOF_MONO_ARRAY;
5692 * mono_array_new_full:
5693 * \param domain domain where the object is created
5694 * \param array_class array class
5695 * \param lengths lengths for each dimension in the array
5696 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5697 * This routine creates a new array object with the given dimensions,
5698 * lower bounds and type.
5701 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5704 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5705 mono_error_cleanup (&error);
5711 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5713 MONO_REQ_GC_UNSAFE_MODE;
5715 uintptr_t byte_len = 0, len, bounds_size;
5718 MonoArrayBounds *bounds;
5724 if (!array_class->inited)
5725 mono_class_init (array_class);
5729 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5730 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5732 if (len > MONO_ARRAY_MAX_INDEX) {
5733 mono_error_set_generic_error (error, "System", "OverflowException", "");
5738 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5740 for (i = 0; i < array_class->rank; ++i) {
5741 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5742 mono_error_set_generic_error (error, "System", "OverflowException", "");
5745 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5746 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5753 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5754 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5760 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5761 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5764 byte_len = (byte_len + 3) & ~3;
5765 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5766 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5769 byte_len += bounds_size;
5772 * Following three lines almost taken from mono_object_new ():
5773 * they need to be kept in sync.
5775 vtable = mono_class_vtable_full (domain, array_class, error);
5776 return_val_if_nok (error, NULL);
5779 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5781 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5783 if (G_UNLIKELY (!o)) {
5784 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5788 array = (MonoArray*)o;
5790 bounds = array->bounds;
5793 for (i = 0; i < array_class->rank; ++i) {
5794 bounds [i].length = lengths [i];
5796 bounds [i].lower_bound = lower_bounds [i];
5805 * \param domain domain where the object is created
5806 * \param eclass element class
5807 * \param n number of array elements
5808 * This routine creates a new szarray with \p n elements of type \p eclass.
5811 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5813 MONO_REQ_GC_UNSAFE_MODE;
5816 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5817 mono_error_cleanup (&error);
5822 * mono_array_new_checked:
5823 * \param domain domain where the object is created
5824 * \param eclass element class
5825 * \param n number of array elements
5826 * \param error set on error
5827 * This routine creates a new szarray with \p n elements of type \p eclass.
5828 * On failure returns NULL and sets \p error.
5831 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5837 ac = mono_array_class_get (eclass, 1);
5840 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5841 return_val_if_nok (error, NULL);
5843 return mono_array_new_specific_checked (vtable, n, error);
5847 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5850 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5851 mono_error_set_pending_exception (&error);
5857 * mono_array_new_specific:
5858 * \param vtable a vtable in the appropriate domain for an initialized class
5859 * \param n number of array elements
5860 * This routine is a fast alternative to \c mono_array_new for code which
5861 * can be sure about the domain it operates in.
5864 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5867 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5868 mono_error_cleanup (&error);
5874 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5876 MONO_REQ_GC_UNSAFE_MODE;
5883 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5884 mono_error_set_generic_error (error, "System", "OverflowException", "");
5888 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5889 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5892 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5894 if (G_UNLIKELY (!o)) {
5895 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5899 return (MonoArray*)o;
5903 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5906 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5907 mono_error_set_pending_exception (&error);
5913 * mono_string_empty_wrapper:
5915 * Returns: The same empty string instance as the managed string.Empty
5918 mono_string_empty_wrapper (void)
5920 MonoDomain *domain = mono_domain_get ();
5921 return mono_string_empty (domain);
5925 * mono_string_empty:
5927 * Returns: The same empty string instance as the managed string.Empty
5930 mono_string_empty (MonoDomain *domain)
5933 g_assert (domain->empty_string);
5934 return domain->empty_string;
5938 * mono_string_new_utf16:
5939 * \param text a pointer to an utf16 string
5940 * \param len the length of the string
5941 * \returns A newly created string object which contains \p text.
5944 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5946 MONO_REQ_GC_UNSAFE_MODE;
5949 MonoString *res = NULL;
5950 res = mono_string_new_utf16_checked (domain, text, len, &error);
5951 mono_error_cleanup (&error);
5957 * mono_string_new_utf16_checked:
5958 * \param text a pointer to an utf16 string
5959 * \param len the length of the string
5960 * \param error written on error.
5961 * \returns A newly created string object which contains \p text.
5962 * On error, returns NULL and sets \p error.
5965 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5967 MONO_REQ_GC_UNSAFE_MODE;
5973 s = mono_string_new_size_checked (domain, len, error);
5975 memcpy (mono_string_chars (s), text, len * 2);
5981 * mono_string_new_utf16_handle:
5982 * \param text a pointer to an utf16 string
5983 * \param len the length of the string
5984 * \param error written on error.
5985 * \returns A newly created string object which contains \p text.
5986 * On error, returns NULL and sets \p error.
5989 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5991 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
5995 * mono_string_new_utf32_checked:
5996 * \param text a pointer to an utf32 string
5997 * \param len the length of the string
5998 * \param error set on failure.
5999 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6002 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6004 MONO_REQ_GC_UNSAFE_MODE;
6007 mono_unichar2 *utf16_output = NULL;
6008 gint32 utf16_len = 0;
6009 GError *gerror = NULL;
6010 glong items_written;
6013 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6016 g_error_free (gerror);
6018 while (utf16_output [utf16_len]) utf16_len++;
6020 s = mono_string_new_size_checked (domain, utf16_len, error);
6021 return_val_if_nok (error, NULL);
6023 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6025 g_free (utf16_output);
6031 * mono_string_new_utf32:
6032 * \param text a pointer to a UTF-32 string
6033 * \param len the length of the string
6034 * \returns A newly created string object which contains \p text.
6037 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6040 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6041 mono_error_cleanup (&error);
6046 * mono_string_new_size:
6047 * \param text a pointer to a UTF-16 string
6048 * \param len the length of the string
6049 * \returns A newly created string object of \p len
6052 mono_string_new_size (MonoDomain *domain, gint32 len)
6055 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6056 mono_error_cleanup (&error);
6062 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6064 MONO_REQ_GC_UNSAFE_MODE;
6072 /* check for overflow */
6073 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6074 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6078 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6079 g_assert (size > 0);
6081 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6084 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6086 if (G_UNLIKELY (!s)) {
6087 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6095 * mono_string_new_len:
6096 * \param text a pointer to an utf8 string
6097 * \param length number of bytes in \p text to consider
6098 * \returns A newly created string object which contains \p text.
6101 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6103 MONO_REQ_GC_UNSAFE_MODE;
6106 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6107 mono_error_cleanup (&error);
6112 * mono_string_new_len_checked:
6113 * \param text a pointer to an utf8 string
6114 * \param length number of bytes in \p text to consider
6115 * \param error set on error
6116 * \returns A newly created string object which contains \p text. On
6117 * failure returns NULL and sets \p error.
6120 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6122 MONO_REQ_GC_UNSAFE_MODE;
6126 GError *eg_error = NULL;
6127 MonoString *o = NULL;
6129 glong items_written;
6131 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6134 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6136 g_error_free (eg_error);
6145 * \param text a pointer to a UTF-8 string
6146 * \deprecated Use \c mono_string_new_checked in new code.
6147 * This function asserts if it cannot allocate a new string.
6148 * \returns A newly created string object which contains \p text.
6151 mono_string_new (MonoDomain *domain, const char *text)
6154 MonoString *res = NULL;
6155 res = mono_string_new_checked (domain, text, &error);
6156 mono_error_assert_ok (&error);
6161 * mono_string_new_checked:
6162 * \param text a pointer to an utf8 string
6163 * \param merror set on error
6164 * \returns A newly created string object which contains \p text.
6165 * On error returns NULL and sets \p merror.
6168 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6170 MONO_REQ_GC_UNSAFE_MODE;
6172 GError *eg_error = NULL;
6173 MonoString *o = NULL;
6175 glong items_written;
6182 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6185 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6187 g_error_free (eg_error);
6191 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6196 MonoString *o = NULL;
6198 if (!g_utf8_validate (text, -1, &end)) {
6199 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6203 len = g_utf8_strlen (text, -1);
6204 o = mono_string_new_size_checked (domain, len, error);
6207 str = mono_string_chars (o);
6209 while (text < end) {
6210 *str++ = g_utf8_get_char (text);
6211 text = g_utf8_next_char (text);
6220 * mono_string_new_wrapper:
6221 * \param text pointer to UTF-8 characters.
6222 * Helper function to create a string object from \p text in the current domain.
6225 mono_string_new_wrapper (const char *text)
6227 MONO_REQ_GC_UNSAFE_MODE;
6229 MonoDomain *domain = mono_domain_get ();
6232 return mono_string_new (domain, text);
6239 * \param class the class of the value
6240 * \param value a pointer to the unboxed data
6241 * \returns A newly created object which contains \p value.
6244 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6247 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6248 mono_error_cleanup (&error);
6253 * mono_value_box_checked:
6254 * \param domain the domain of the new object
6255 * \param class the class of the value
6256 * \param value a pointer to the unboxed data
6257 * \param error set on error
6258 * \returns A newly created object which contains \p value. On failure
6259 * returns NULL and sets \p error.
6262 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6264 MONO_REQ_GC_UNSAFE_MODE;
6271 g_assert (klass->valuetype);
6272 if (mono_class_is_nullable (klass))
6273 return mono_nullable_box ((guint8 *)value, klass, error);
6275 vtable = mono_class_vtable (domain, klass);
6278 size = mono_class_instance_size (klass);
6279 res = mono_object_new_alloc_specific_checked (vtable, error);
6280 return_val_if_nok (error, NULL);
6282 size = size - sizeof (MonoObject);
6285 g_assert (size == mono_class_value_size (klass, NULL));
6286 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6288 #if NO_UNALIGNED_ACCESS
6289 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6293 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6296 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6299 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6302 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6305 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6309 if (klass->has_finalize) {
6310 mono_object_register_finalizer (res);
6311 return_val_if_nok (error, NULL);
6318 * \param dest destination pointer
6319 * \param src source pointer
6320 * \param klass a valuetype class
6321 * Copy a valuetype from \p src to \p dest. This function must be used
6322 * when \p klass contains reference fields.
6325 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6327 MONO_REQ_GC_UNSAFE_MODE;
6329 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6333 * mono_value_copy_array:
6334 * \param dest destination array
6335 * \param dest_idx index in the \p dest array
6336 * \param src source pointer
6337 * \param count number of items
6338 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6339 * This function must be used when \p klass contains references fields.
6340 * Overlap is handled.
6343 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6345 MONO_REQ_GC_UNSAFE_MODE;
6347 int size = mono_array_element_size (dest->obj.vtable->klass);
6348 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6349 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6350 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6354 * mono_object_get_domain:
6355 * \param obj object to query
6356 * \returns the \c MonoDomain where the object is hosted
6359 mono_object_get_domain (MonoObject *obj)
6361 MONO_REQ_GC_UNSAFE_MODE;
6363 return mono_object_domain (obj);
6367 * mono_object_get_class:
6368 * \param obj object to query
6369 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6370 * \returns the \c MonoClass of the object.
6373 mono_object_get_class (MonoObject *obj)
6375 MONO_REQ_GC_UNSAFE_MODE;
6377 return mono_object_class (obj);
6380 * mono_object_get_size:
6381 * \param o object to query
6382 * \returns the size, in bytes, of \p o
6385 mono_object_get_size (MonoObject* o)
6387 MONO_REQ_GC_UNSAFE_MODE;
6389 MonoClass* klass = mono_object_class (o);
6390 if (klass == mono_defaults.string_class) {
6391 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6392 } else if (o->vtable->rank) {
6393 MonoArray *array = (MonoArray*)o;
6394 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6395 if (array->bounds) {
6398 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6402 return mono_class_instance_size (klass);
6407 * mono_object_unbox:
6408 * \param obj object to unbox
6409 * \returns a pointer to the start of the valuetype boxed in this
6412 * This method will assert if the object passed is not a valuetype.
6415 mono_object_unbox (MonoObject *obj)
6417 MONO_REQ_GC_UNSAFE_MODE;
6419 /* add assert for valuetypes? */
6420 g_assert (obj->vtable->klass->valuetype);
6421 return ((char*)obj) + sizeof (MonoObject);
6425 * mono_object_isinst:
6426 * \param obj an object
6427 * \param klass a pointer to a class
6428 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6431 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6433 MONO_REQ_GC_UNSAFE_MODE;
6435 HANDLE_FUNCTION_ENTER ();
6436 MONO_HANDLE_DCL (MonoObject, obj);
6438 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6439 mono_error_cleanup (&error);
6440 HANDLE_FUNCTION_RETURN_OBJ (result);
6445 * mono_object_isinst_checked:
6446 * \param obj an object
6447 * \param klass a pointer to a class
6448 * \param error set on error
6449 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6450 * On failure returns NULL and sets \p error.
6453 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6455 MONO_REQ_GC_UNSAFE_MODE;
6457 HANDLE_FUNCTION_ENTER ();
6459 MONO_HANDLE_DCL (MonoObject, obj);
6460 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6461 HANDLE_FUNCTION_RETURN_OBJ (result);
6465 * mono_object_handle_isinst:
6466 * \param obj an object
6467 * \param klass a pointer to a class
6468 * \param error set on error
6469 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6470 * On failure returns NULL and sets \p error.
6473 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6478 mono_class_init (klass);
6480 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6481 return mono_object_handle_isinst_mbyref (obj, klass, error);
6484 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6486 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6487 MONO_HANDLE_ASSIGN (result, obj);
6492 * mono_object_isinst_mbyref:
6495 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6497 MONO_REQ_GC_UNSAFE_MODE;
6499 HANDLE_FUNCTION_ENTER ();
6501 MONO_HANDLE_DCL (MonoObject, obj);
6502 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6503 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6504 HANDLE_FUNCTION_RETURN_OBJ (result);
6508 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6512 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6514 if (MONO_HANDLE_IS_NULL (obj))
6517 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6519 if (mono_class_is_interface (klass)) {
6520 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6521 MONO_HANDLE_ASSIGN (result, obj);
6525 /* casting an array one of the invariant interfaces that must act as such */
6526 if (klass->is_array_special_interface) {
6527 if (mono_class_is_assignable_from (klass, vt->klass)) {
6528 MONO_HANDLE_ASSIGN (result, obj);
6533 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6534 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6535 MONO_HANDLE_ASSIGN (result, obj);
6539 MonoClass *oklass = vt->klass;
6540 if (mono_class_is_transparent_proxy (oklass)){
6541 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6542 oklass = remote_class->proxy_class;
6545 mono_class_setup_supertypes (klass);
6546 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6547 MONO_HANDLE_ASSIGN (result, obj);
6551 #ifndef DISABLE_REMOTING
6552 if (mono_class_is_transparent_proxy (vt->klass))
6554 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6555 if (!custom_type_info)
6557 MonoDomain *domain = mono_domain_get ();
6558 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6559 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6560 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6561 MonoMethod *im = NULL;
6564 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6566 mono_error_set_not_supported (error, "Linked away.");
6569 im = mono_object_handle_get_virtual_method (rp, im, error);
6574 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6578 pa [0] = MONO_HANDLE_RAW (reftype);
6579 pa [1] = MONO_HANDLE_RAW (obj);
6580 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6584 if (*(MonoBoolean *) mono_object_unbox(res)) {
6585 /* Update the vtable of the remote type, so it can safely cast to this new type */
6586 mono_upgrade_remote_class (domain, obj, klass, error);
6589 MONO_HANDLE_ASSIGN (result, obj);
6592 #endif /* DISABLE_REMOTING */
6598 * mono_object_castclass_mbyref:
6599 * \param obj an object
6600 * \param klass a pointer to a class
6601 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6604 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6606 MONO_REQ_GC_UNSAFE_MODE;
6607 HANDLE_FUNCTION_ENTER ();
6609 MONO_HANDLE_DCL (MonoObject, obj);
6610 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6611 if (MONO_HANDLE_IS_NULL (obj))
6613 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6614 mono_error_cleanup (&error);
6616 HANDLE_FUNCTION_RETURN_OBJ (result);
6620 MonoDomain *orig_domain;
6626 str_lookup (MonoDomain *domain, gpointer user_data)
6628 MONO_REQ_GC_UNSAFE_MODE;
6630 LDStrInfo *info = (LDStrInfo *)user_data;
6631 if (info->res || domain == info->orig_domain)
6633 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6637 mono_string_get_pinned (MonoString *str, MonoError *error)
6639 MONO_REQ_GC_UNSAFE_MODE;
6643 /* We only need to make a pinned version of a string if this is a moving GC */
6644 if (!mono_gc_is_moving ())
6648 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6649 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6651 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6652 news->length = mono_string_length (str);
6654 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6660 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6662 MONO_REQ_GC_UNSAFE_MODE;
6664 MonoGHashTable *ldstr_table;
6665 MonoString *s, *res;
6670 domain = ((MonoObject *)str)->vtable->domain;
6671 ldstr_table = domain->ldstr_table;
6673 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6679 /* Allocate outside the lock */
6681 s = mono_string_get_pinned (str, error);
6682 return_val_if_nok (error, NULL);
6685 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6690 mono_g_hash_table_insert (ldstr_table, s, s);
6695 LDStrInfo ldstr_info;
6696 ldstr_info.orig_domain = domain;
6697 ldstr_info.ins = str;
6698 ldstr_info.res = NULL;
6700 mono_domain_foreach (str_lookup, &ldstr_info);
6701 if (ldstr_info.res) {
6703 * the string was already interned in some other domain:
6704 * intern it in the current one as well.
6706 mono_g_hash_table_insert (ldstr_table, str, str);
6716 * mono_string_is_interned:
6717 * \param o String to probe
6718 * \returns Whether the string has been interned.
6721 mono_string_is_interned (MonoString *o)
6724 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6725 /* This function does not fail. */
6726 mono_error_assert_ok (&error);
6731 * mono_string_intern:
6732 * \param o String to intern
6733 * Interns the string passed.
6734 * \returns The interned string.
6737 mono_string_intern (MonoString *str)
6740 MonoString *result = mono_string_intern_checked (str, &error);
6741 mono_error_assert_ok (&error);
6746 * mono_string_intern_checked:
6747 * \param o String to intern
6748 * \param error set on error.
6749 * Interns the string passed.
6750 * \returns The interned string. On failure returns NULL and sets \p error
6753 mono_string_intern_checked (MonoString *str, MonoError *error)
6755 MONO_REQ_GC_UNSAFE_MODE;
6759 return mono_string_is_interned_lookup (str, TRUE, error);
6764 * \param domain the domain where the string will be used.
6765 * \param image a metadata context
6766 * \param idx index into the user string table.
6767 * Implementation for the \c ldstr opcode.
6768 * \returns a loaded string from the \p image / \p idx combination.
6771 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6774 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6775 mono_error_cleanup (&error);
6780 * mono_ldstr_checked:
6781 * \param domain the domain where the string will be used.
6782 * \param image a metadata context
6783 * \param idx index into the user string table.
6784 * \param error set on error.
6785 * Implementation for the \c ldstr opcode.
6786 * \returns A loaded string from the \p image / \p idx combination.
6787 * On failure returns NULL and sets \p error.
6790 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6792 MONO_REQ_GC_UNSAFE_MODE;
6795 if (image->dynamic) {
6796 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6799 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6800 return NULL; /*FIXME we should probably be raising an exception here*/
6801 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6807 * mono_ldstr_metadata_sig
6808 * \param domain the domain for the string
6809 * \param sig the signature of a metadata string
6810 * \param error set on error
6811 * \returns a \c MonoString for a string stored in the metadata. On
6812 * failure returns NULL and sets \p error.
6815 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6817 MONO_REQ_GC_UNSAFE_MODE;
6820 const char *str = sig;
6821 MonoString *o, *interned;
6824 len2 = mono_metadata_decode_blob_size (str, &str);
6827 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6828 return_val_if_nok (error, NULL);
6829 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6832 guint16 *p2 = (guint16*)mono_string_chars (o);
6833 for (i = 0; i < len2; ++i) {
6834 *p2 = GUINT16_FROM_LE (*p2);
6840 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6843 return interned; /* o will get garbage collected */
6845 o = mono_string_get_pinned (o, error);
6848 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6850 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6862 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6866 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6872 GError *gerror = NULL;
6876 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6877 return NULL; /*FIXME we should probably be raising an exception here*/
6878 str = mono_metadata_user_string (image, idx);
6880 len2 = mono_metadata_decode_blob_size (str, &str);
6883 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6885 mono_error_set_argument (error, "string", "%s", gerror->message);
6886 g_error_free (gerror);
6889 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6890 if (len2 > written) {
6891 /* allocate the total length and copy the part of the string that has been converted */
6892 char *as2 = (char *)g_malloc0 (len2);
6893 memcpy (as2, as, written);
6902 * mono_string_to_utf8:
6903 * \param s a \c System.String
6904 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6905 * \returns the UTF-8 representation for \p s.
6906 * The resulting buffer needs to be freed with \c mono_free().
6909 mono_string_to_utf8 (MonoString *s)
6911 MONO_REQ_GC_UNSAFE_MODE;
6914 char *result = mono_string_to_utf8_checked (s, &error);
6916 if (!is_ok (&error)) {
6917 mono_error_cleanup (&error);
6924 * mono_string_to_utf8_checked:
6925 * \param s a \c System.String
6926 * \param error a \c MonoError.
6927 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6928 * \p error to determine whether the conversion was successful.
6929 * The resulting buffer should be freed with \c mono_free().
6932 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6934 MONO_REQ_GC_UNSAFE_MODE;
6938 GError *gerror = NULL;
6946 return g_strdup ("");
6948 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6950 mono_error_set_argument (error, "string", "%s", gerror->message);
6951 g_error_free (gerror);
6954 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6955 if (s->length > written) {
6956 /* allocate the total length and copy the part of the string that has been converted */
6957 char *as2 = (char *)g_malloc0 (s->length);
6958 memcpy (as2, as, written);
6967 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
6969 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
6973 * mono_string_to_utf8_ignore:
6974 * \param s a MonoString
6975 * Converts a \c MonoString to its UTF-8 representation. Will ignore
6976 * invalid surrogate pairs.
6977 * The resulting buffer should be freed with \c mono_free().
6980 mono_string_to_utf8_ignore (MonoString *s)
6982 MONO_REQ_GC_UNSAFE_MODE;
6991 return g_strdup ("");
6993 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6995 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6996 if (s->length > written) {
6997 /* allocate the total length and copy the part of the string that has been converted */
6998 char *as2 = (char *)g_malloc0 (s->length);
6999 memcpy (as2, as, written);
7008 * mono_string_to_utf8_image_ignore:
7009 * \param s a \c System.String
7010 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7013 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7015 MONO_REQ_GC_UNSAFE_MODE;
7017 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7021 * mono_string_to_utf8_mp_ignore:
7022 * \param s a \c System.String
7023 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7026 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7028 MONO_REQ_GC_UNSAFE_MODE;
7030 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7035 * mono_string_to_utf16:
7036 * \param s a \c MonoString
7037 * \returns a null-terminated array of the UTF-16 chars
7038 * contained in \p s. The result must be freed with \c g_free().
7039 * This is a temporary helper until our string implementation
7040 * is reworked to always include the null-terminating char.
7043 mono_string_to_utf16 (MonoString *s)
7045 MONO_REQ_GC_UNSAFE_MODE;
7052 as = (char *)g_malloc ((s->length * 2) + 2);
7053 as [(s->length * 2)] = '\0';
7054 as [(s->length * 2) + 1] = '\0';
7057 return (gunichar2 *)(as);
7060 memcpy (as, mono_string_chars(s), s->length * 2);
7061 return (gunichar2 *)(as);
7065 * mono_string_to_utf32:
7066 * \param s a \c MonoString
7067 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7068 * contained in \p s. The result must be freed with \c g_free().
7071 mono_string_to_utf32 (MonoString *s)
7073 MONO_REQ_GC_UNSAFE_MODE;
7075 mono_unichar4 *utf32_output = NULL;
7076 GError *error = NULL;
7077 glong items_written;
7082 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7085 g_error_free (error);
7087 return utf32_output;
7091 * mono_string_from_utf16:
7092 * \param data the UTF-16 string (LPWSTR) to convert
7093 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7094 * \returns a \c MonoString.
7097 mono_string_from_utf16 (gunichar2 *data)
7100 MonoString *result = mono_string_from_utf16_checked (data, &error);
7101 mono_error_cleanup (&error);
7106 * mono_string_from_utf16_checked:
7107 * \param data the UTF-16 string (LPWSTR) to convert
7108 * \param error set on error
7109 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7110 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7113 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7116 MONO_REQ_GC_UNSAFE_MODE;
7119 MonoDomain *domain = mono_domain_get ();
7125 while (data [len]) len++;
7127 return mono_string_new_utf16_checked (domain, data, len, error);
7131 * mono_string_from_utf32:
7132 * \param data the UTF-32 string (LPWSTR) to convert
7133 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7134 * \returns a \c MonoString.
7137 mono_string_from_utf32 (mono_unichar4 *data)
7140 MonoString *result = mono_string_from_utf32_checked (data, &error);
7141 mono_error_cleanup (&error);
7146 * mono_string_from_utf32_checked:
7147 * \param data the UTF-32 string (LPWSTR) to convert
7148 * \param error set on error
7149 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7150 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7153 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7155 MONO_REQ_GC_UNSAFE_MODE;
7158 MonoString* result = NULL;
7159 mono_unichar2 *utf16_output = NULL;
7160 GError *gerror = NULL;
7161 glong items_written;
7167 while (data [len]) len++;
7169 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7172 g_error_free (gerror);
7174 result = mono_string_from_utf16_checked (utf16_output, error);
7175 g_free (utf16_output);
7180 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7182 MONO_REQ_GC_UNSAFE_MODE;
7189 r = mono_string_to_utf8_ignore (s);
7191 r = mono_string_to_utf8_checked (s, error);
7192 if (!mono_error_ok (error))
7199 len = strlen (r) + 1;
7201 mp_s = (char *)mono_mempool_alloc (mp, len);
7203 mp_s = (char *)mono_image_alloc (image, len);
7205 memcpy (mp_s, r, len);
7213 * mono_string_to_utf8_image:
7214 * \param s a \c System.String
7215 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7218 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7220 MONO_REQ_GC_UNSAFE_MODE;
7222 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7226 * mono_string_to_utf8_mp:
7227 * \param s a \c System.String
7228 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7231 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7233 MONO_REQ_GC_UNSAFE_MODE;
7235 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7239 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7242 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7244 eh_callbacks = *cbs;
7247 MonoRuntimeExceptionHandlingCallbacks *
7248 mono_get_eh_callbacks (void)
7250 return &eh_callbacks;
7254 * mono_raise_exception:
7255 * \param ex exception object
7256 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7259 mono_raise_exception (MonoException *ex)
7261 MONO_REQ_GC_UNSAFE_MODE;
7264 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7265 * that will cause gcc to omit the function epilog, causing problems when
7266 * the JIT tries to walk the stack, since the return address on the stack
7267 * will point into the next function in the executable, not this one.
7269 eh_callbacks.mono_raise_exception (ex);
7273 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7275 MONO_REQ_GC_UNSAFE_MODE;
7277 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7281 * mono_wait_handle_new:
7282 * \param domain Domain where the object will be created
7283 * \param handle Handle for the wait handle
7284 * \param error set on error.
7285 * \returns A new \c MonoWaitHandle created in the given domain for the
7286 * given handle. On failure returns NULL and sets \p error.
7289 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7291 MONO_REQ_GC_UNSAFE_MODE;
7293 MonoWaitHandle *res;
7294 gpointer params [1];
7295 static MonoMethod *handle_set;
7298 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7299 return_val_if_nok (error, NULL);
7301 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7303 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7305 params [0] = &handle;
7307 mono_runtime_invoke_checked (handle_set, res, params, error);
7312 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7314 MONO_REQ_GC_UNSAFE_MODE;
7316 static MonoClassField *f_safe_handle = NULL;
7319 if (!f_safe_handle) {
7320 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7321 g_assert (f_safe_handle);
7324 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7330 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7332 MONO_REQ_GC_UNSAFE_MODE;
7334 RuntimeInvokeFunction runtime_invoke;
7338 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7339 MonoMethod *method = mono_get_context_capture_method ();
7340 MonoMethod *wrapper;
7343 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7344 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7345 return_val_if_nok (error, NULL);
7346 domain->capture_context_method = mono_compile_method_checked (method, error);
7347 return_val_if_nok (error, NULL);
7350 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7352 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7355 * mono_async_result_new:
7356 * \param domain domain where the object will be created.
7357 * \param handle wait handle.
7358 * \param state state to pass to AsyncResult
7359 * \param data C closure data.
7360 * \param error set on error.
7361 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7362 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7363 * On failure returns NULL and sets \p error.
7366 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7368 MONO_REQ_GC_UNSAFE_MODE;
7371 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7372 return_val_if_nok (error, NULL);
7373 MonoObject *context = mono_runtime_capture_context (domain, error);
7374 return_val_if_nok (error, NULL);
7375 /* we must capture the execution context from the original thread */
7377 MONO_OBJECT_SETREF (res, execution_context, context);
7378 /* note: result may be null if the flow is suppressed */
7381 res->data = (void **)data;
7382 MONO_OBJECT_SETREF (res, object_data, object_data);
7383 MONO_OBJECT_SETREF (res, async_state, state);
7384 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7385 return_val_if_nok (error, NULL);
7387 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7389 res->sync_completed = FALSE;
7390 res->completed = FALSE;
7396 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7398 MONO_REQ_GC_UNSAFE_MODE;
7405 g_assert (ares->async_delegate);
7407 ac = (MonoAsyncCall*) ares->object_data;
7409 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7410 if (mono_error_set_pending_exception (&error))
7413 gpointer wait_event = NULL;
7415 ac->msg->exc = NULL;
7417 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7419 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7420 mono_threads_begin_abort_protected_block ();
7422 if (!ac->msg->exc) {
7423 MonoException *ex = mono_error_convert_to_exception (&error);
7424 ac->msg->exc = (MonoObject *)ex;
7426 mono_error_cleanup (&error);
7429 MONO_OBJECT_SETREF (ac, res, res);
7431 mono_monitor_enter ((MonoObject*) ares);
7432 ares->completed = 1;
7434 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7435 mono_monitor_exit ((MonoObject*) ares);
7437 if (wait_event != NULL)
7438 mono_w32event_set (wait_event);
7440 error_init (&error); //the else branch would leave it in an undefined state
7442 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7444 mono_threads_end_abort_protected_block ();
7446 if (mono_error_set_pending_exception (&error))
7454 mono_message_init (MonoDomain *domain,
7455 MonoMethodMessage *this_obj,
7456 MonoReflectionMethod *method,
7457 MonoArray *out_args,
7460 MONO_REQ_GC_UNSAFE_MODE;
7462 static MonoMethod *init_message_method = NULL;
7464 if (!init_message_method) {
7465 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7466 g_assert (init_message_method != NULL);
7470 /* FIXME set domain instead? */
7471 g_assert (domain == mono_domain_get ());
7478 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7479 return is_ok (error);
7482 #ifndef DISABLE_REMOTING
7484 * mono_remoting_invoke:
7485 * \param real_proxy pointer to a \c RealProxy object
7486 * \param msg The \c MonoMethodMessage to execute
7487 * \param exc used to store exceptions
7488 * \param out_args used to store output arguments
7489 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7490 * \c IMessage interface and it is not trivial to extract results from there. So
7491 * we call an helper method \c PrivateInvoke instead of calling
7492 * \c RealProxy::Invoke() directly.
7493 * \returns the result object.
7496 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7498 MONO_REQ_GC_UNSAFE_MODE;
7501 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7508 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7511 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7513 mono_error_set_not_supported (error, "Linked away.");
7516 real_proxy->vtable->domain->private_invoke_method = im;
7519 pa [0] = real_proxy;
7524 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7525 return_val_if_nok (error, NULL);
7532 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7533 MonoObject **exc, MonoArray **out_args, MonoError *error)
7535 MONO_REQ_GC_UNSAFE_MODE;
7537 static MonoClass *object_array_klass;
7542 MonoMethodSignature *sig;
7544 int i, j, outarg_count = 0;
7546 #ifndef DISABLE_REMOTING
7547 if (target && mono_object_is_transparent_proxy (target)) {
7548 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7549 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7550 target = tp->rp->unwrapped_server;
7552 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7557 domain = mono_domain_get ();
7558 method = msg->method->method;
7559 sig = mono_method_signature (method);
7561 for (i = 0; i < sig->param_count; i++) {
7562 if (sig->params [i]->byref)
7566 if (!object_array_klass) {
7569 klass = mono_array_class_get (mono_defaults.object_class, 1);
7572 mono_memory_barrier ();
7573 object_array_klass = klass;
7576 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7577 return_val_if_nok (error, NULL);
7579 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7582 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7583 return_val_if_nok (error, NULL);
7585 for (i = 0, j = 0; i < sig->param_count; i++) {
7586 if (sig->params [i]->byref) {
7588 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7589 mono_array_setref (*out_args, j, arg);
7598 * prepare_to_string_method:
7600 * @target: Set to @obj or unboxed value if a valuetype
7602 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7605 prepare_to_string_method (MonoObject *obj, void **target)
7607 MONO_REQ_GC_UNSAFE_MODE;
7609 static MonoMethod *to_string = NULL;
7617 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7619 method = mono_object_get_virtual_method (obj, to_string);
7621 // Unbox value type if needed
7622 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7623 *target = mono_object_unbox (obj);
7629 * mono_object_to_string:
7630 * \param obj The object
7631 * \param exc Any exception thrown by \c ToString. May be NULL.
7632 * \returns the result of calling \c ToString on an object.
7635 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7638 MonoString *s = NULL;
7640 MonoMethod *method = prepare_to_string_method (obj, &target);
7642 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7643 if (*exc == NULL && !mono_error_ok (&error))
7644 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7646 mono_error_cleanup (&error);
7648 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7649 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7656 * mono_object_to_string_checked:
7657 * \param obj The object
7658 * \param error Set on error.
7659 * \returns the result of calling \c ToString() on an object. If the
7660 * method cannot be invoked or if it raises an exception, sets \p error
7664 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7668 MonoMethod *method = prepare_to_string_method (obj, &target);
7669 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7673 * mono_object_try_to_string:
7674 * \param obj The object
7675 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7676 * \param error Set if method cannot be invoked.
7677 * \returns the result of calling \c ToString() on an object. If the
7678 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7682 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7687 MonoMethod *method = prepare_to_string_method (obj, &target);
7688 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7694 get_native_backtrace (MonoException *exc_raw)
7696 HANDLE_FUNCTION_ENTER ();
7697 MONO_HANDLE_DCL(MonoException, exc);
7698 char * trace = mono_exception_handle_get_native_backtrace (exc);
7699 HANDLE_FUNCTION_RETURN_VAL (trace);
7703 * mono_print_unhandled_exception:
7704 * \param exc The exception
7705 * Prints the unhandled exception.
7708 mono_print_unhandled_exception (MonoObject *exc)
7710 MONO_REQ_GC_UNSAFE_MODE;
7713 char *message = (char*)"";
7714 gboolean free_message = FALSE;
7717 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7718 message = g_strdup ("OutOfMemoryException");
7719 free_message = TRUE;
7720 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7721 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7722 free_message = TRUE;
7725 if (((MonoException*)exc)->native_trace_ips) {
7726 message = get_native_backtrace ((MonoException*)exc);
7727 free_message = TRUE;
7729 MonoObject *other_exc = NULL;
7730 str = mono_object_try_to_string (exc, &other_exc, &error);
7731 if (other_exc == NULL && !is_ok (&error))
7732 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7734 mono_error_cleanup (&error);
7736 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7737 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7739 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7740 original_backtrace, nested_backtrace);
7742 g_free (original_backtrace);
7743 g_free (nested_backtrace);
7744 free_message = TRUE;
7746 message = mono_string_to_utf8_checked (str, &error);
7747 if (!mono_error_ok (&error)) {
7748 mono_error_cleanup (&error);
7749 message = (char *) "";
7751 free_message = TRUE;
7758 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7759 * exc->vtable->klass->name, message);
7761 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7768 * mono_delegate_ctor_with_method:
7769 * \param this pointer to an uninitialized delegate object
7770 * \param target target object
7771 * \param addr pointer to native code
7772 * \param method method
7773 * \param error set on error.
7774 * Initialize a delegate and sets a specific method, not the one
7775 * associated with \p addr. This is useful when sharing generic code.
7776 * In that case \p addr will most probably not be associated with the
7777 * correct instantiation of the method.
7778 * On failure returns FALSE and sets \p error.
7781 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7783 MONO_REQ_GC_UNSAFE_MODE;
7786 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7788 g_assert (this_obj);
7791 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7794 delegate->method = method;
7796 mono_stats.delegate_creations++;
7798 #ifndef DISABLE_REMOTING
7799 if (target && mono_object_is_transparent_proxy (target)) {
7801 method = mono_marshal_get_remoting_invoke (method);
7802 #ifdef ENABLE_INTERPRETER
7803 g_error ("need RuntimeMethod in method_ptr when using interpreter");
7805 delegate->method_ptr = mono_compile_method_checked (method, error);
7806 return_val_if_nok (error, FALSE);
7807 MONO_OBJECT_SETREF (delegate, target, target);
7811 delegate->method_ptr = addr;
7812 MONO_OBJECT_SETREF (delegate, target, target);
7815 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7816 if (callbacks.init_delegate)
7817 callbacks.init_delegate (delegate);
7822 * mono_delegate_ctor:
7823 * \param this pointer to an uninitialized delegate object
7824 * \param target target object
7825 * \param addr pointer to native code
7826 * \param error set on error.
7827 * This is used to initialize a delegate.
7828 * On failure returns FALSE and sets \p error.
7831 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7833 MONO_REQ_GC_UNSAFE_MODE;
7836 MonoDomain *domain = mono_domain_get ();
7838 MonoMethod *method = NULL;
7842 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7844 if (!ji && domain != mono_get_root_domain ())
7845 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7847 method = mono_jit_info_get_method (ji);
7848 g_assert (!mono_class_is_gtd (method->klass));
7851 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7855 * mono_method_call_message_new:
7856 * \param method method to encapsulate
7857 * \param params parameters to the method
7858 * \param invoke optional, delegate invoke.
7859 * \param cb async callback delegate.
7860 * \param state state passed to the async callback.
7861 * \param error set on error.
7862 * Translates arguments pointers into a \c MonoMethodMessage.
7863 * On failure returns NULL and sets \p error.
7866 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7867 MonoDelegate **cb, MonoObject **state, MonoError *error)
7869 MONO_REQ_GC_UNSAFE_MODE;
7873 MonoDomain *domain = mono_domain_get ();
7874 MonoMethodSignature *sig = mono_method_signature (method);
7875 MonoMethodMessage *msg;
7878 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7879 return_val_if_nok (error, NULL);
7882 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7883 return_val_if_nok (error, NULL);
7884 mono_message_init (domain, msg, rm, NULL, error);
7885 return_val_if_nok (error, NULL);
7886 count = sig->param_count - 2;
7888 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7889 return_val_if_nok (error, NULL);
7890 mono_message_init (domain, msg, rm, NULL, error);
7891 return_val_if_nok (error, NULL);
7892 count = sig->param_count;
7895 for (i = 0; i < count; i++) {
7900 if (sig->params [i]->byref)
7901 vpos = *((gpointer *)params [i]);
7905 klass = mono_class_from_mono_type (sig->params [i]);
7907 if (klass->valuetype) {
7908 arg = mono_value_box_checked (domain, klass, vpos, error);
7909 return_val_if_nok (error, NULL);
7911 arg = *((MonoObject **)vpos);
7913 mono_array_setref (msg->args, i, arg);
7916 if (cb != NULL && state != NULL) {
7917 *cb = *((MonoDelegate **)params [i]);
7919 *state = *((MonoObject **)params [i]);
7926 * mono_method_return_message_restore:
7928 * Restore results from message based processing back to arguments pointers
7931 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7933 MONO_REQ_GC_UNSAFE_MODE;
7937 MonoMethodSignature *sig = mono_method_signature (method);
7938 int i, j, type, size, out_len;
7940 if (out_args == NULL)
7942 out_len = mono_array_length (out_args);
7946 for (i = 0, j = 0; i < sig->param_count; i++) {
7947 MonoType *pt = sig->params [i];
7952 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7956 arg = (char *)mono_array_get (out_args, gpointer, j);
7959 g_assert (type != MONO_TYPE_VOID);
7961 if (MONO_TYPE_IS_REFERENCE (pt)) {
7962 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7965 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7966 size = mono_class_value_size (klass, NULL);
7967 if (klass->has_references)
7968 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7970 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7972 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7973 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7982 #ifndef DISABLE_REMOTING
7985 * mono_load_remote_field:
7986 * \param this pointer to an object
7987 * \param klass klass of the object containing \p field
7988 * \param field the field to load
7989 * \param res a storage to store the result
7990 * This method is called by the runtime on attempts to load fields of
7991 * transparent proxy objects. \p this points to such TP, \p klass is the class of
7992 * the object containing \p field. \p res is a storage location which can be
7993 * used to store the result.
7994 * \returns an address pointing to the value of field.
7997 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8000 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8001 mono_error_cleanup (&error);
8006 * mono_load_remote_field_checked:
8007 * \param this pointer to an object
8008 * \param klass klass of the object containing \p field
8009 * \param field the field to load
8010 * \param res a storage to store the result
8011 * \param error set on error
8012 * This method is called by the runtime on attempts to load fields of
8013 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8014 * the object containing \p field. \p res is a storage location which can be
8015 * used to store the result.
8016 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8019 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8021 MONO_REQ_GC_UNSAFE_MODE;
8023 static MonoMethod *getter = NULL;
8027 MonoDomain *domain = mono_domain_get ();
8028 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8029 MonoClass *field_class;
8030 MonoMethodMessage *msg;
8031 MonoArray *out_args;
8035 g_assert (mono_object_is_transparent_proxy (this_obj));
8036 g_assert (res != NULL);
8038 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8039 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8044 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8046 mono_error_set_not_supported (error, "Linked away.");
8051 field_class = mono_class_from_mono_type (field->type);
8053 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8054 return_val_if_nok (error, NULL);
8055 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8056 return_val_if_nok (error, NULL);
8057 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8058 return_val_if_nok (error, NULL);
8059 mono_message_init (domain, msg, rm, out_args, error);
8060 return_val_if_nok (error, NULL);
8062 full_name = mono_type_get_full_name (klass);
8063 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8064 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8067 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8068 return_val_if_nok (error, NULL);
8071 mono_error_set_exception_instance (error, (MonoException *)exc);
8075 if (mono_array_length (out_args) == 0)
8078 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8080 if (field_class->valuetype) {
8081 return ((char *)*res) + sizeof (MonoObject);
8087 * mono_load_remote_field_new:
8091 * Missing documentation.
8094 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8098 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8099 mono_error_cleanup (&error);
8104 * mono_load_remote_field_new_checked:
8105 * \param this pointer to an object
8106 * \param klass klass of the object containing \p field
8107 * \param field the field to load
8108 * \param error set on error.
8109 * This method is called by the runtime on attempts to load fields of
8110 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8111 * the object containing \p field.
8112 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8115 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8117 MONO_REQ_GC_UNSAFE_MODE;
8121 static MonoMethod *tp_load = NULL;
8123 g_assert (mono_object_is_transparent_proxy (this_obj));
8126 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8128 mono_error_set_not_supported (error, "Linked away.");
8133 /* MonoType *type = mono_class_get_type (klass); */
8139 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8143 * mono_store_remote_field:
8144 * \param this_obj pointer to an object
8145 * \param klass klass of the object containing \p field
8146 * \param field the field to load
8147 * \param val the value/object to store
8148 * This method is called by the runtime on attempts to store fields of
8149 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8150 * the object containing \p field. \p val is the new value to store in \p field.
8153 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8156 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8157 mono_error_cleanup (&error);
8161 * mono_store_remote_field_checked:
8162 * \param this_obj pointer to an object
8163 * \param klass klass of the object containing \p field
8164 * \param field the field to load
8165 * \param val the value/object to store
8166 * \param error set on error
8167 * This method is called by the runtime on attempts to store fields of
8168 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8169 * the object containing \p field. \p val is the new value to store in \p field.
8170 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8173 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8176 MONO_REQ_GC_UNSAFE_MODE;
8180 MonoDomain *domain = mono_domain_get ();
8181 MonoClass *field_class;
8184 g_assert (mono_object_is_transparent_proxy (this_obj));
8186 field_class = mono_class_from_mono_type (field->type);
8188 if (field_class->valuetype) {
8189 arg = mono_value_box_checked (domain, field_class, val, error);
8190 return_val_if_nok (error, FALSE);
8192 arg = *((MonoObject**)val);
8195 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8199 * mono_store_remote_field_new:
8204 * Missing documentation
8207 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8210 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8211 mono_error_cleanup (&error);
8215 * mono_store_remote_field_new_checked:
8221 * Missing documentation
8224 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8226 MONO_REQ_GC_UNSAFE_MODE;
8228 static MonoMethod *tp_store = NULL;
8232 g_assert (mono_object_is_transparent_proxy (this_obj));
8235 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8237 mono_error_set_not_supported (error, "Linked away.");
8247 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8248 return is_ok (error);
8253 * mono_create_ftnptr:
8255 * Given a function address, create a function descriptor for it.
8256 * This is only needed on some platforms.
8259 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8261 return callbacks.create_ftnptr (domain, addr);
8265 * mono_get_addr_from_ftnptr:
8267 * Given a pointer to a function descriptor, return the function address.
8268 * This is only needed on some platforms.
8271 mono_get_addr_from_ftnptr (gpointer descr)
8273 return callbacks.get_addr_from_ftnptr (descr);
8277 * mono_string_chars:
8278 * \param s a \c MonoString
8279 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8282 mono_string_chars (MonoString *s)
8284 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8290 * mono_string_length:
8291 * \param s MonoString
8292 * \returns the length in characters of the string
8295 mono_string_length (MonoString *s)
8297 MONO_REQ_GC_UNSAFE_MODE;
8303 * mono_string_handle_length:
8304 * \param s \c MonoString
8305 * \returns the length in characters of the string
8308 mono_string_handle_length (MonoStringHandle s)
8310 MONO_REQ_GC_UNSAFE_MODE;
8312 return MONO_HANDLE_GETVAL (s, length);
8317 * mono_array_length:
8318 * \param array a \c MonoArray*
8319 * \returns the total number of elements in the array. This works for
8320 * both vectors and multidimensional arrays.
8323 mono_array_length (MonoArray *array)
8325 MONO_REQ_GC_UNSAFE_MODE;
8327 return array->max_length;
8331 * mono_array_addr_with_size:
8332 * \param array a \c MonoArray*
8333 * \param size size of the array elements
8334 * \param idx index into the array
8335 * Use this function to obtain the address for the \p idx item on the
8336 * \p array containing elements of size \p size.
8338 * This method performs no bounds checking or type checking.
8339 * \returns the address of the \p idx element in the array.
8342 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8344 MONO_REQ_GC_UNSAFE_MODE;
8346 return ((char*)(array)->vector) + size * idx;
8351 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8353 MonoDomain *domain = mono_domain_get ();
8361 len = g_list_length (list);
8362 res = mono_array_new_checked (domain, eclass, len, error);
8363 return_val_if_nok (error, NULL);
8365 for (i = 0; list; list = list->next, i++)
8366 mono_array_set (res, gpointer, i, list->data);
8373 * The following section is purely to declare prototypes and
8374 * document the API, as these C files are processed by our
8380 * \param array array to alter
8381 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8382 * \param index index into the array
8383 * \param value value to set
8384 * Value Type version: This sets the \p index's element of the \p array
8385 * with elements of size sizeof(type) to the provided \p value.
8387 * This macro does not attempt to perform type checking or bounds checking.
8389 * Use this to set value types in a \c MonoArray.
8391 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8396 * mono_array_setref:
8397 * \param array array to alter
8398 * \param index index into the array
8399 * \param value value to set
8400 * Reference Type version. This sets the \p index's element of the
8401 * \p array with elements of size sizeof(type) to the provided \p value.
8403 * This macro does not attempt to perform type checking or bounds checking.
8405 * Use this to reference types in a \c MonoArray.
8407 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8413 * \param array array on which to operate on
8414 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8415 * \param index index into the array
8417 * Use this macro to retrieve the \p index element of an \p array and
8418 * extract the value assuming that the elements of the array match
8419 * the provided type value.
8421 * This method can be used with both arrays holding value types and
8422 * reference types. For reference types, the \p type parameter should
8423 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8425 * This macro does not attempt to perform type checking or bounds checking.
8427 * \returns The element at the \p index position in the \p array.
8429 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)