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>
52 #include <mono/utils/unlocked.h>
55 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61 free_main_args (void);
64 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
67 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
70 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
72 /* Class lazy loading functions */
73 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
74 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
75 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
76 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
77 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
80 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
81 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
82 static mono_mutex_t ldstr_section;
86 * mono_runtime_object_init:
87 * \param this_obj the object to initialize
88 * This function calls the zero-argument constructor (which must
89 * exist) for the given object.
92 mono_runtime_object_init (MonoObject *this_obj)
95 mono_runtime_object_init_checked (this_obj, &error);
96 mono_error_assert_ok (&error);
100 * mono_runtime_object_init_checked:
101 * \param this_obj the object to initialize
102 * \param error set on error.
103 * This function calls the zero-argument constructor (which must
104 * exist) for the given object and returns TRUE on success, or FALSE
105 * on error and sets \p error.
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
110 MONO_REQ_GC_UNSAFE_MODE;
112 MonoMethod *method = NULL;
113 MonoClass *klass = this_obj->vtable->klass;
116 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
120 if (method->klass->valuetype)
121 this_obj = (MonoObject *)mono_object_unbox (this_obj);
123 mono_runtime_invoke_checked (method, this_obj, NULL, error);
124 return is_ok (error);
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an
133 2.2. If successful, record this thread as responsible for
134 initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread
136 waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock. This thread
138 will now see an incompletely initialized state for the type,
139 but no deadlock will arise.
140 2.2.3 If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock,
145 awaken any threads waiting for this type to be initialized,
152 MonoNativeThreadId initializing_tid;
153 guint32 waiting_count;
156 /* condvar used to wait for 'done' becoming TRUE */
158 } TypeInitializationLock;
160 /* for locking access to type_initialization_hash and blocked_thread_hash */
161 static MonoCoopMutex type_initialization_section;
164 mono_type_initialization_lock (void)
166 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
167 mono_coop_mutex_lock (&type_initialization_section);
171 mono_type_initialization_unlock (void)
173 mono_coop_mutex_unlock (&type_initialization_section);
177 mono_type_init_lock (TypeInitializationLock *lock)
179 MONO_REQ_GC_NEUTRAL_MODE;
181 mono_coop_mutex_lock (&lock->mutex);
185 mono_type_init_unlock (TypeInitializationLock *lock)
187 mono_coop_mutex_unlock (&lock->mutex);
190 /* from vtable to lock */
191 static GHashTable *type_initialization_hash;
193 /* from thread id to thread id being waited on */
194 static GHashTable *blocked_thread_hash;
197 static MonoThread *main_thread;
199 /* Functions supplied by the runtime */
200 static MonoRuntimeCallbacks callbacks;
203 * mono_thread_set_main:
204 * \param thread thread to set as the main thread
205 * This function can be used to instruct the runtime to treat \p thread
206 * as the main thread, ie, the thread that would normally execute the \c Main
207 * method. This basically means that at the end of \p thread, the runtime will
208 * wait for the existing foreground threads to quit and other such details.
211 mono_thread_set_main (MonoThread *thread)
213 MONO_REQ_GC_UNSAFE_MODE;
215 static gboolean registered = FALSE;
218 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
222 main_thread = thread;
226 * mono_thread_get_main:
229 mono_thread_get_main (void)
231 MONO_REQ_GC_UNSAFE_MODE;
237 mono_type_initialization_init (void)
239 mono_coop_mutex_init_recursive (&type_initialization_section);
240 type_initialization_hash = g_hash_table_new (NULL, NULL);
241 blocked_thread_hash = g_hash_table_new (NULL, NULL);
242 mono_os_mutex_init_recursive (&ldstr_section);
243 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
247 mono_type_initialization_cleanup (void)
250 /* This is causing race conditions with
251 * mono_release_type_locks
253 mono_coop_mutex_destroy (&type_initialization_section);
254 g_hash_table_destroy (type_initialization_hash);
255 type_initialization_hash = NULL;
257 mono_os_mutex_destroy (&ldstr_section);
258 g_hash_table_destroy (blocked_thread_hash);
259 blocked_thread_hash = NULL;
265 * get_type_init_exception_for_vtable:
267 * Return the stored type initialization exception for VTABLE.
269 static MonoException*
270 get_type_init_exception_for_vtable (MonoVTable *vtable)
272 MONO_REQ_GC_UNSAFE_MODE;
275 MonoDomain *domain = vtable->domain;
276 MonoClass *klass = vtable->klass;
280 if (!vtable->init_failed)
281 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
284 * If the initializing thread was rudely aborted, the exception is not stored
288 mono_domain_lock (domain);
289 if (domain->type_init_exception_hash)
290 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
291 mono_domain_unlock (domain);
294 if (klass->name_space && *klass->name_space)
295 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
297 full_name = g_strdup (klass->name);
298 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
300 return_val_if_nok (&error, NULL);
307 * mono_runtime_class_init:
308 * \param vtable vtable that needs to be initialized
309 * This routine calls the class constructor for \p vtable.
312 mono_runtime_class_init (MonoVTable *vtable)
314 MONO_REQ_GC_UNSAFE_MODE;
317 mono_runtime_class_init_full (vtable, &error);
318 mono_error_assert_ok (&error);
322 * Returns TRUE if the lock was freed.
323 * LOCKING: Caller should hold type_initialization_lock.
326 unref_type_lock (TypeInitializationLock *lock)
328 --lock->waiting_count;
329 if (lock->waiting_count == 0) {
330 mono_coop_mutex_destroy (&lock->mutex);
331 mono_coop_cond_destroy (&lock->cond);
340 * mono_runtime_class_init_full:
341 * \param vtable that neeeds to be initialized
342 * \param error set on error
343 * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
346 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
348 MONO_REQ_GC_UNSAFE_MODE;
350 MonoMethod *method = NULL;
353 MonoDomain *domain = vtable->domain;
354 TypeInitializationLock *lock;
355 MonoNativeThreadId tid;
356 int do_initialization = 0;
357 MonoDomain *last_domain = NULL;
358 gboolean pending_tae = FALSE;
362 if (vtable->initialized)
365 klass = vtable->klass;
367 if (!klass->image->checked_module_cctor) {
368 mono_image_check_for_module_cctor (klass->image);
369 if (klass->image->has_module_cctor) {
370 MonoClass *module_klass;
371 MonoVTable *module_vtable;
373 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
378 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
381 if (!mono_runtime_class_init_full (module_vtable, error))
385 method = mono_class_get_cctor (klass);
387 vtable->initialized = 1;
391 tid = mono_native_thread_id_get ();
394 * Due some preprocessing inside a global lock. If we are the first thread
395 * trying to initialize this class, create a separate lock+cond var, and
396 * acquire it before leaving the global lock. The other threads will wait
400 mono_type_initialization_lock ();
401 /* double check... */
402 if (vtable->initialized) {
403 mono_type_initialization_unlock ();
406 if (vtable->init_failed) {
407 mono_type_initialization_unlock ();
409 /* The type initialization already failed once, rethrow the same exception */
410 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
413 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
415 /* This thread will get to do the initialization */
416 if (mono_domain_get () != domain) {
417 /* Transfer into the target domain */
418 last_domain = mono_domain_get ();
419 if (!mono_domain_set (domain, FALSE)) {
420 vtable->initialized = 1;
421 mono_type_initialization_unlock ();
422 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
426 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
427 mono_coop_mutex_init_recursive (&lock->mutex);
428 mono_coop_cond_init (&lock->cond);
429 lock->initializing_tid = tid;
430 lock->waiting_count = 1;
432 g_hash_table_insert (type_initialization_hash, vtable, lock);
433 do_initialization = 1;
436 TypeInitializationLock *pending_lock;
438 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
439 mono_type_initialization_unlock ();
442 /* see if the thread doing the initialization is already blocked on this thread */
443 gboolean is_blocked = TRUE;
444 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
445 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
446 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
447 if (!pending_lock->done) {
448 mono_type_initialization_unlock ();
451 /* the thread doing the initialization is blocked on this thread,
452 but on a lock that has already been freed. It just hasn't got
458 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
460 ++lock->waiting_count;
461 /* record the fact that we are waiting on the initializing thread */
463 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
465 mono_type_initialization_unlock ();
467 if (do_initialization) {
468 MonoException *exc = NULL;
470 /* We are holding the per-vtable lock, do the actual initialization */
472 mono_threads_begin_abort_protected_block ();
473 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
474 mono_threads_end_abort_protected_block ();
476 //exception extracted, error will be set to the right value later
477 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
478 exc = mono_error_convert_to_exception (error);
480 mono_error_cleanup (error);
484 /* If the initialization failed, mark the class as unusable. */
485 /* Avoid infinite loops */
487 (klass->image == mono_defaults.corlib &&
488 !strcmp (klass->name_space, "System") &&
489 !strcmp (klass->name, "TypeInitializationException")))) {
490 vtable->init_failed = 1;
492 if (klass->name_space && *klass->name_space)
493 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
495 full_name = g_strdup (klass->name);
497 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
500 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
503 * Store the exception object so it could be thrown on subsequent
506 mono_domain_lock (domain);
507 if (!domain->type_init_exception_hash)
508 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");
509 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
510 mono_domain_unlock (domain);
514 mono_domain_set (last_domain, TRUE);
516 /* Signal to the other threads that we are done */
517 mono_type_init_lock (lock);
519 mono_coop_cond_broadcast (&lock->cond);
520 mono_type_init_unlock (lock);
523 * This can happen if the cctor self-aborts. We need to reactivate tae
524 * (next interruption checkpoint will throw it) and make sure we won't
525 * throw tie for the type.
527 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
529 mono_thread_resume_interruption (FALSE);
532 /* this just blocks until the initializing thread is done */
533 mono_type_init_lock (lock);
535 mono_coop_cond_wait (&lock->cond, &lock->mutex);
536 mono_type_init_unlock (lock);
539 /* Do cleanup and setting vtable->initialized inside the global lock again */
540 mono_type_initialization_lock ();
541 if (!do_initialization)
542 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
543 gboolean deleted = unref_type_lock (lock);
545 g_hash_table_remove (type_initialization_hash, vtable);
546 /* Have to set this here since we check it inside the global lock */
547 if (do_initialization && !vtable->init_failed)
548 vtable->initialized = 1;
549 mono_type_initialization_unlock ();
551 /* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
552 if (vtable->init_failed && !pending_tae) {
553 /* Either we were the initializing thread or we waited for the initialization */
554 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
561 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
563 MONO_REQ_GC_NEUTRAL_MODE;
565 MonoVTable *vtable = (MonoVTable*)key;
567 TypeInitializationLock *lock = (TypeInitializationLock*) value;
568 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 * Have to set this since it cannot be set by the normal code in
572 * mono_runtime_class_init (). In this case, the exception object is not stored,
573 * and get_type_init_exception_for_class () needs to be aware of this.
575 mono_type_init_lock (lock);
576 vtable->init_failed = 1;
577 mono_coop_cond_broadcast (&lock->cond);
578 mono_type_init_unlock (lock);
579 gboolean deleted = unref_type_lock (lock);
587 mono_release_type_locks (MonoInternalThread *thread)
589 MONO_REQ_GC_UNSAFE_MODE;
591 mono_type_initialization_lock ();
592 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
593 mono_type_initialization_unlock ();
596 #ifndef DISABLE_REMOTING
599 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
601 if (!callbacks.create_remoting_trampoline)
602 g_error ("remoting not installed");
603 return callbacks.create_remoting_trampoline (domain, method, target, error);
608 static MonoImtTrampolineBuilder imt_trampoline_builder;
609 static gboolean always_build_imt_trampolines;
611 #if (MONO_IMT_SIZE > 32)
612 #error "MONO_IMT_SIZE cannot be larger than 32"
616 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
618 memcpy (&callbacks, cbs, sizeof (*cbs));
621 MonoRuntimeCallbacks*
622 mono_get_runtime_callbacks (void)
628 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
630 imt_trampoline_builder = func;
634 mono_set_always_build_imt_trampolines (gboolean value)
636 always_build_imt_trampolines = value;
640 * mono_compile_method:
641 * \param method The method to compile.
642 * This JIT-compiles the method, and returns the pointer to the native code
646 mono_compile_method (MonoMethod *method)
649 gpointer result = mono_compile_method_checked (method, &error);
650 mono_error_cleanup (&error);
655 * mono_compile_method_checked:
656 * \param method The method to compile.
657 * \param error set on error.
658 * This JIT-compiles the method, and returns the pointer to the native code
659 * produced. On failure returns NULL and sets \p error.
662 mono_compile_method_checked (MonoMethod *method, MonoError *error)
666 MONO_REQ_GC_NEUTRAL_MODE
670 g_assert (callbacks.compile_method);
671 res = callbacks.compile_method (method, error);
676 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
680 MONO_REQ_GC_NEUTRAL_MODE;
683 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
688 mono_runtime_create_delegate_trampoline (MonoClass *klass)
690 MONO_REQ_GC_NEUTRAL_MODE
692 g_assert (callbacks.create_delegate_trampoline);
693 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
697 * mono_runtime_free_method:
698 * \param domain domain where the method is hosted
699 * \param method method to release
700 * This routine is invoked to free the resources associated with
701 * a method that has been JIT compiled. This is used to discard
702 * methods that were used only temporarily (for example, used in marshalling)
705 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
707 MONO_REQ_GC_NEUTRAL_MODE
709 if (callbacks.free_method)
710 callbacks.free_method (domain, method);
712 mono_method_clear_object (domain, method);
714 mono_free_method (method);
718 * The vtables in the root appdomain are assumed to be reachable by other
719 * roots, and we don't use typed allocation in the other domains.
722 /* The sync block is no longer a GC pointer */
723 #define GC_HEADER_BITMAP (0)
725 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
728 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
730 MONO_REQ_GC_NEUTRAL_MODE;
732 MonoClassField *field;
738 max_size = mono_class_data_size (klass) / sizeof (gpointer);
740 max_size = klass->instance_size / sizeof (gpointer);
741 if (max_size > size) {
742 g_assert (offset <= 0);
743 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
747 /* An Ephemeron cannot be marked by sgen */
748 if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
750 memset (bitmap, 0, size / 8);
754 for (p = klass; p != NULL; p = p->parent) {
755 gpointer iter = NULL;
756 while ((field = mono_class_get_fields (p, &iter))) {
760 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
762 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
765 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
768 /* FIXME: should not happen, flag as type load error */
769 if (field->type->byref)
772 if (static_fields && field->offset == -1)
776 pos = field->offset / sizeof (gpointer);
779 type = mono_type_get_underlying_type (field->type);
780 switch (type->type) {
784 case MONO_TYPE_FNPTR:
786 case MONO_TYPE_STRING:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_ARRAY:
791 g_assert ((field->offset % sizeof(gpointer)) == 0);
793 g_assert (pos < size || pos <= max_size);
794 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 *max_set = MAX (*max_set, pos);
797 case MONO_TYPE_GENERICINST:
798 if (!mono_type_generic_inst_is_valuetype (type)) {
799 g_assert ((field->offset % sizeof(gpointer)) == 0);
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802 *max_set = MAX (*max_set, pos);
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 if (fclass->has_references) {
810 /* remove the object header */
811 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
825 case MONO_TYPE_BOOLEAN:
829 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
840 * mono_class_compute_bitmap:
842 * Mono internal function to compute a bitmap of reference fields in a class.
845 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
847 MONO_REQ_GC_NEUTRAL_MODE;
849 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
854 * similar to the above, but sets the bits in the bitmap for any non-ref field
855 * and ignores static fields
858 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
860 MonoClassField *field;
865 max_size = class->instance_size / sizeof (gpointer);
866 if (max_size >= size) {
867 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 for (p = class; p != NULL; p = p->parent) {
871 gpointer iter = NULL;
872 while ((field = mono_class_get_fields (p, &iter))) {
875 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
877 /* FIXME: should not happen, flag as type load error */
878 if (field->type->byref)
881 pos = field->offset / sizeof (gpointer);
884 type = mono_type_get_underlying_type (field->type);
885 switch (type->type) {
886 #if SIZEOF_VOID_P == 8
890 case MONO_TYPE_FNPTR:
895 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
896 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
897 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 #if SIZEOF_VOID_P == 4
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
917 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
918 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
919 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 case MONO_TYPE_BOOLEAN:
925 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
927 case MONO_TYPE_STRING:
928 case MONO_TYPE_SZARRAY:
929 case MONO_TYPE_CLASS:
930 case MONO_TYPE_OBJECT:
931 case MONO_TYPE_ARRAY:
933 case MONO_TYPE_GENERICINST:
934 if (!mono_type_generic_inst_is_valuetype (type)) {
939 case MONO_TYPE_VALUETYPE: {
940 MonoClass *fclass = mono_class_from_mono_type (field->type);
941 /* remove the object header */
942 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
946 g_assert_not_reached ();
955 * mono_class_insecure_overlapping:
956 * check if a class with explicit layout has references and non-references
957 * fields overlapping.
959 * Returns: TRUE if it is insecure to load the type.
962 mono_class_insecure_overlapping (MonoClass *klass)
966 gsize default_bitmap [4] = {0};
968 gsize default_nrbitmap [4] = {0};
969 int i, insecure = FALSE;
972 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
973 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
975 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
976 int idx = i % (sizeof (bitmap [0]) * 8);
977 if (bitmap [idx] & nrbitmap [idx]) {
982 if (bitmap != default_bitmap)
984 if (nrbitmap != default_nrbitmap)
987 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
995 ves_icall_string_alloc (int length)
998 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
999 mono_error_set_pending_exception (&error);
1004 /* LOCKING: Acquires the loader lock */
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1008 MONO_REQ_GC_NEUTRAL_MODE;
1012 gsize default_bitmap [4] = {0};
1013 MonoGCDescriptor gc_descr;
1016 mono_class_init (klass);
1018 if (klass->gc_descr_inited)
1021 bitmap = default_bitmap;
1022 if (klass == mono_defaults.string_class) {
1023 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1024 } else if (klass->rank) {
1025 mono_class_compute_gc_descriptor (klass->element_class);
1026 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1028 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1029 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1030 class->name_space, class->name);*/
1032 /* remove the object header */
1033 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1034 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));
1035 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1036 class->name_space, class->name);*/
1037 if (bitmap != default_bitmap)
1041 /*static int count = 0;
1044 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1045 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1047 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1048 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1050 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1051 if (bitmap != default_bitmap)
1055 /* Publish the data */
1056 mono_loader_lock ();
1057 klass->gc_descr = gc_descr;
1058 mono_memory_barrier ();
1059 klass->gc_descr_inited = TRUE;
1060 mono_loader_unlock ();
1064 * field_is_special_static:
1065 * @fklass: The MonoClass to look up.
1066 * @field: The MonoClassField describing the field.
1068 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1069 * SPECIAL_STATIC_NONE otherwise.
1072 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1074 MONO_REQ_GC_NEUTRAL_MODE;
1077 MonoCustomAttrInfo *ainfo;
1079 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1080 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1083 for (i = 0; i < ainfo->num_attrs; ++i) {
1084 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1085 if (klass->image == mono_defaults.corlib) {
1086 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1087 mono_custom_attrs_free (ainfo);
1088 return SPECIAL_STATIC_THREAD;
1090 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1091 mono_custom_attrs_free (ainfo);
1092 return SPECIAL_STATIC_CONTEXT;
1096 mono_custom_attrs_free (ainfo);
1097 return SPECIAL_STATIC_NONE;
1100 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1101 #define mix(a,b,c) { \
1102 a -= c; a ^= rot(c, 4); c += b; \
1103 b -= a; b ^= rot(a, 6); a += c; \
1104 c -= b; c ^= rot(b, 8); b += a; \
1105 a -= c; a ^= rot(c,16); c += b; \
1106 b -= a; b ^= rot(a,19); a += c; \
1107 c -= b; c ^= rot(b, 4); b += a; \
1109 #define final(a,b,c) { \
1110 c ^= b; c -= rot(b,14); \
1111 a ^= c; a -= rot(c,11); \
1112 b ^= a; b -= rot(a,25); \
1113 c ^= b; c -= rot(b,16); \
1114 a ^= c; a -= rot(c,4); \
1115 b ^= a; b -= rot(a,14); \
1116 c ^= b; c -= rot(b,24); \
1120 * mono_method_get_imt_slot:
1122 * The IMT slot is embedded into AOTed code, so this must return the same value
1123 * for the same method across all executions. This means:
1124 * - pointers shouldn't be used as hash values.
1125 * - mono_metadata_str_hash () should be used for hashing strings.
1128 mono_method_get_imt_slot (MonoMethod *method)
1130 MONO_REQ_GC_NEUTRAL_MODE;
1132 MonoMethodSignature *sig;
1134 guint32 *hashes_start, *hashes;
1138 /* This can be used to stress tests the collision code */
1142 * We do this to simplify generic sharing. It will hurt
1143 * performance in cases where a class implements two different
1144 * instantiations of the same generic interface.
1145 * The code in build_imt_slots () depends on this.
1147 if (method->is_inflated)
1148 method = ((MonoMethodInflated*)method)->declaring;
1150 sig = mono_method_signature (method);
1151 hashes_count = sig->param_count + 4;
1152 hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1153 hashes = hashes_start;
1155 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1156 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1157 method->klass->name_space, method->klass->name, method->name);
1160 /* Initialize hashes */
1161 hashes [0] = mono_metadata_str_hash (method->klass->name);
1162 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1163 hashes [2] = mono_metadata_str_hash (method->name);
1164 hashes [3] = mono_metadata_type_hash (sig->ret);
1165 for (i = 0; i < sig->param_count; i++) {
1166 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1169 /* Setup internal state */
1170 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1172 /* Handle most of the hashes */
1173 while (hashes_count > 3) {
1182 /* Handle the last 3 hashes (all the case statements fall through) */
1183 switch (hashes_count) {
1184 case 3 : c += hashes [2];
1185 case 2 : b += hashes [1];
1186 case 1 : a += hashes [0];
1188 case 0: /* nothing left to add */
1192 g_free (hashes_start);
1193 /* Report the result */
1194 return c % MONO_IMT_SIZE;
1203 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1204 MONO_REQ_GC_NEUTRAL_MODE;
1206 guint32 imt_slot = mono_method_get_imt_slot (method);
1207 MonoImtBuilderEntry *entry;
1209 if (slot_num >= 0 && imt_slot != slot_num) {
1210 /* we build just a single imt slot and this is not it */
1214 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1215 entry->key = method;
1216 entry->value.vtable_slot = vtable_slot;
1217 entry->next = imt_builder [imt_slot];
1218 if (imt_builder [imt_slot] != NULL) {
1219 entry->children = imt_builder [imt_slot]->children + 1;
1220 if (entry->children == 1) {
1221 UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1222 *imt_collisions_bitmap |= (1 << imt_slot);
1225 entry->children = 0;
1226 UnlockedIncrement (&mono_stats.imt_used_slots);
1228 imt_builder [imt_slot] = entry;
1231 char *method_name = mono_method_full_name (method, TRUE);
1232 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1233 method, method_name, imt_slot, vtable_slot, entry->children);
1234 g_free (method_name);
1241 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1243 MonoMethod *method = e->key;
1244 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1248 method->klass->name_space,
1249 method->klass->name,
1252 printf (" * %s: NULL\n", message);
1258 compare_imt_builder_entries (const void *p1, const void *p2) {
1259 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1260 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1262 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1266 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1268 MONO_REQ_GC_NEUTRAL_MODE;
1270 int count = end - start;
1271 int chunk_start = out_array->len;
1274 for (i = start; i < end; ++i) {
1275 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1276 item->key = sorted_array [i]->key;
1277 item->value = sorted_array [i]->value;
1278 item->has_target_code = sorted_array [i]->has_target_code;
1279 item->is_equals = TRUE;
1281 item->check_target_idx = out_array->len + 1;
1283 item->check_target_idx = 0;
1284 g_ptr_array_add (out_array, item);
1287 int middle = start + count / 2;
1288 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1290 item->key = sorted_array [middle]->key;
1291 item->is_equals = FALSE;
1292 g_ptr_array_add (out_array, item);
1293 imt_emit_ir (sorted_array, start, middle, out_array);
1294 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1300 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1301 MONO_REQ_GC_NEUTRAL_MODE;
1303 int number_of_entries = entries->children + 1;
1304 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1305 GPtrArray *result = g_ptr_array_new ();
1306 MonoImtBuilderEntry *current_entry;
1309 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1310 sorted_array [i] = current_entry;
1312 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1314 /*for (i = 0; i < number_of_entries; i++) {
1315 print_imt_entry (" sorted array:", sorted_array [i], i);
1318 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1320 g_free (sorted_array);
1325 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1327 MONO_REQ_GC_NEUTRAL_MODE;
1329 if (imt_builder_entry != NULL) {
1330 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1331 /* No collision, return the vtable slot contents */
1332 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1334 /* Collision, build the trampoline */
1335 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1338 result = imt_trampoline_builder (vtable, domain,
1339 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1340 for (i = 0; i < imt_ir->len; ++i)
1341 g_free (g_ptr_array_index (imt_ir, i));
1342 g_ptr_array_free (imt_ir, TRUE);
1354 static MonoImtBuilderEntry*
1355 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1358 * LOCKING: requires the loader and domain locks.
1362 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1364 MONO_REQ_GC_NEUTRAL_MODE;
1368 guint32 imt_collisions_bitmap = 0;
1369 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1370 int method_count = 0;
1371 gboolean record_method_count_for_max_collisions = FALSE;
1372 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1375 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1377 for (i = 0; i < klass->interface_offsets_count; ++i) {
1378 MonoClass *iface = klass->interfaces_packed [i];
1379 int interface_offset = klass->interface_offsets_packed [i];
1380 int method_slot_in_interface, vt_slot;
1382 if (mono_class_has_variant_generic_params (iface))
1383 has_variant_iface = TRUE;
1385 mono_class_setup_methods (iface);
1386 vt_slot = interface_offset;
1387 int mcount = mono_class_get_method_count (iface);
1388 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1391 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1393 * The imt slot of the method is the same as for its declaring method,
1394 * see the comment in mono_method_get_imt_slot (), so we can
1395 * avoid inflating methods which will be discarded by
1396 * add_imt_builder_entry anyway.
1398 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1399 if (mono_method_get_imt_slot (method) != slot_num) {
1404 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1405 if (method->is_generic) {
1406 has_generic_virtual = TRUE;
1411 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1412 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1417 if (extra_interfaces) {
1418 int interface_offset = klass->vtable_size;
1420 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1421 MonoClass* iface = (MonoClass *)list_item->data;
1422 int method_slot_in_interface;
1423 int mcount = mono_class_get_method_count (iface);
1424 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1425 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1427 if (method->is_generic)
1428 has_generic_virtual = TRUE;
1429 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1431 interface_offset += mcount;
1434 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1435 /* overwrite the imt slot only if we're building all the entries or if
1436 * we're building this specific one
1438 if (slot_num < 0 || i == slot_num) {
1439 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1442 if (imt_builder [i]) {
1443 MonoImtBuilderEntry *entry;
1445 /* Link entries with imt_builder [i] */
1446 for (entry = entries; entry->next; entry = entry->next) {
1448 MonoMethod *method = (MonoMethod*)entry->key;
1449 char *method_name = mono_method_full_name (method, TRUE);
1450 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1451 g_free (method_name);
1454 entry->next = imt_builder [i];
1455 entries->children += imt_builder [i]->children + 1;
1457 imt_builder [i] = entries;
1460 if (has_generic_virtual || has_variant_iface) {
1462 * There might be collisions later when the the trampoline is expanded.
1464 imt_collisions_bitmap |= (1 << i);
1467 * The IMT trampoline might be called with an instance of one of the
1468 * generic virtual methods, so has to fallback to the IMT trampoline.
1470 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1472 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1475 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1479 if (imt_builder [i] != NULL) {
1480 int methods_in_slot = imt_builder [i]->children + 1;
1481 if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1482 UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1483 record_method_count_for_max_collisions = TRUE;
1485 method_count += methods_in_slot;
1489 UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1490 if (record_method_count_for_max_collisions) {
1491 UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1494 for (i = 0; i < MONO_IMT_SIZE; i++) {
1495 MonoImtBuilderEntry* entry = imt_builder [i];
1496 while (entry != NULL) {
1497 MonoImtBuilderEntry* next = entry->next;
1502 g_free (imt_builder);
1503 /* we OR the bitmap since we may build just a single imt slot at a time */
1504 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1508 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1509 MONO_REQ_GC_NEUTRAL_MODE;
1511 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1515 * mono_vtable_build_imt_slot:
1516 * \param vtable virtual object table struct
1517 * \param imt_slot slot in the IMT table
1518 * Fill the given \p imt_slot in the IMT table of \p vtable with
1519 * a trampoline or a trampoline for the case of collisions.
1520 * This is part of the internal mono API.
1521 * LOCKING: Take the domain lock.
1524 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1526 MONO_REQ_GC_NEUTRAL_MODE;
1528 gpointer *imt = (gpointer*)vtable;
1529 imt -= MONO_IMT_SIZE;
1530 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1532 /* no support for extra interfaces: the proxy objects will need
1533 * to build the complete IMT
1534 * Update and heck needs to ahppen inside the proper domain lock, as all
1535 * the changes made to a MonoVTable.
1537 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1538 mono_domain_lock (vtable->domain);
1539 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1540 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1541 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1542 mono_domain_unlock (vtable->domain);
1543 mono_loader_unlock ();
1546 #define THUNK_THRESHOLD 10
1549 * mono_method_alloc_generic_virtual_trampoline:
1550 * \param domain a domain
1551 * \param size size in bytes
1552 * Allocs \p size bytes to be used for the code of a generic virtual
1553 * trampoline. It's either allocated from the domain's code manager or
1554 * reused from a previously invalidated piece.
1555 * LOCKING: The domain lock must be held.
1558 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1560 MONO_REQ_GC_NEUTRAL_MODE;
1562 static gboolean inited = FALSE;
1563 static int generic_virtual_trampolines_size = 0;
1566 mono_counters_register ("Generic virtual trampoline bytes",
1567 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1570 generic_virtual_trampolines_size += size;
1572 return mono_domain_code_reserve (domain, size);
1575 typedef struct _GenericVirtualCase {
1579 struct _GenericVirtualCase *next;
1580 } GenericVirtualCase;
1583 * get_generic_virtual_entries:
1585 * Return IMT entries for the generic virtual method instances and
1586 * variant interface methods for vtable slot
1589 static MonoImtBuilderEntry*
1590 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1592 MONO_REQ_GC_NEUTRAL_MODE;
1594 GenericVirtualCase *list;
1595 MonoImtBuilderEntry *entries;
1597 mono_domain_lock (domain);
1598 if (!domain->generic_virtual_cases)
1599 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1601 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1604 for (; list; list = list->next) {
1605 MonoImtBuilderEntry *entry;
1607 if (list->count < THUNK_THRESHOLD)
1610 entry = g_new0 (MonoImtBuilderEntry, 1);
1611 entry->key = list->method;
1612 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1613 entry->has_target_code = 1;
1615 entry->children = entries->children + 1;
1616 entry->next = entries;
1620 mono_domain_unlock (domain);
1622 /* FIXME: Leaking memory ? */
1627 * \param domain a domain
1628 * \param vtable_slot pointer to the vtable slot
1629 * \param method the inflated generic virtual method
1630 * \param code the method's code
1632 * Registers a call via unmanaged code to a generic virtual method
1633 * instantiation or variant interface method. If the number of calls reaches a threshold
1634 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1635 * virtual method trampoline.
1638 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1639 gpointer *vtable_slot,
1640 MonoMethod *method, gpointer code)
1642 MONO_REQ_GC_NEUTRAL_MODE;
1644 static gboolean inited = FALSE;
1645 static int num_added = 0;
1646 static int num_freed = 0;
1648 GenericVirtualCase *gvc, *list;
1649 MonoImtBuilderEntry *entries;
1653 mono_domain_lock (domain);
1654 if (!domain->generic_virtual_cases)
1655 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1658 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1659 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1663 /* Check whether the case was already added */
1664 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1667 if (gvc->method == method)
1672 /* If not found, make a new one */
1674 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1675 gvc->method = method;
1678 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1680 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1685 if (++gvc->count == THUNK_THRESHOLD) {
1686 gpointer *old_thunk = (void **)*vtable_slot;
1687 gpointer vtable_trampoline = NULL;
1688 gpointer imt_trampoline = NULL;
1690 if ((gpointer)vtable_slot < (gpointer)vtable) {
1691 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1692 int imt_slot = MONO_IMT_SIZE + displacement;
1694 /* Force the rebuild of the trampoline at the next call */
1695 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1696 *vtable_slot = imt_trampoline;
1698 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1700 entries = get_generic_virtual_entries (domain, vtable_slot);
1702 sorted = imt_sort_slot_entries (entries);
1704 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1708 MonoImtBuilderEntry *next = entries->next;
1713 for (i = 0; i < sorted->len; ++i)
1714 g_free (g_ptr_array_index (sorted, i));
1715 g_ptr_array_free (sorted, TRUE);
1717 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1722 mono_domain_unlock (domain);
1725 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1728 * mono_class_vtable:
1729 * \param domain the application domain
1730 * \param class the class to initialize
1731 * VTables are domain specific because we create domain specific code, and
1732 * they contain the domain specific static class data.
1733 * On failure, NULL is returned, and \c class->exception_type is set.
1736 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1739 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1740 mono_error_cleanup (&error);
1745 * mono_class_vtable_full:
1746 * \param domain the application domain
1747 * \param class the class to initialize
1748 * \param error set on failure.
1749 * VTables are domain specific because we create domain specific code, and
1750 * they contain the domain specific static class data.
1753 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1755 MONO_REQ_GC_UNSAFE_MODE;
1757 MonoClassRuntimeInfo *runtime_info;
1763 if (mono_class_has_failure (klass)) {
1764 mono_error_set_for_class_failure (error, klass);
1768 /* this check can be inlined in jitted code, too */
1769 runtime_info = klass->runtime_info;
1770 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1771 return runtime_info->domain_vtables [domain->domain_id];
1772 return mono_class_create_runtime_vtable (domain, klass, error);
1776 * mono_class_try_get_vtable:
1777 * \param domain the application domain
1778 * \param class the class to initialize
1779 * This function tries to get the associated vtable from \p class if
1780 * it was already created.
1783 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1785 MONO_REQ_GC_NEUTRAL_MODE;
1787 MonoClassRuntimeInfo *runtime_info;
1791 runtime_info = klass->runtime_info;
1792 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1793 return runtime_info->domain_vtables [domain->domain_id];
1798 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1800 MONO_REQ_GC_NEUTRAL_MODE;
1802 size_t alloc_offset;
1805 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1806 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1807 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1809 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1810 g_assert ((imt_table_bytes & 7) == 4);
1817 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1821 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1823 MONO_REQ_GC_UNSAFE_MODE;
1826 MonoClassRuntimeInfo *runtime_info, *old_info;
1827 MonoClassField *field;
1829 int i, vtable_slots;
1830 size_t imt_table_bytes;
1832 guint32 vtable_size, class_size;
1834 gpointer *interface_offsets;
1838 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1839 mono_domain_lock (domain);
1840 runtime_info = klass->runtime_info;
1841 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1842 mono_domain_unlock (domain);
1843 mono_loader_unlock ();
1844 return runtime_info->domain_vtables [domain->domain_id];
1846 if (!klass->inited || mono_class_has_failure (klass)) {
1847 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1848 mono_domain_unlock (domain);
1849 mono_loader_unlock ();
1850 mono_error_set_for_class_failure (error, klass);
1855 /* Array types require that their element type be valid*/
1856 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1857 MonoClass *element_class = klass->element_class;
1858 if (!element_class->inited)
1859 mono_class_init (element_class);
1861 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1862 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1863 mono_class_setup_vtable (element_class);
1865 if (mono_class_has_failure (element_class)) {
1866 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1867 if (!mono_class_has_failure (klass))
1868 mono_class_set_type_load_failure (klass, "");
1869 mono_domain_unlock (domain);
1870 mono_loader_unlock ();
1871 mono_error_set_for_class_failure (error, klass);
1877 * For some classes, mono_class_init () already computed klass->vtable_size, and
1878 * that is all that is needed because of the vtable trampolines.
1880 if (!klass->vtable_size)
1881 mono_class_setup_vtable (klass);
1883 if (mono_class_is_ginst (klass) && !klass->vtable)
1884 mono_class_check_vtable_constraints (klass, NULL);
1886 /* Initialize klass->has_finalize */
1887 mono_class_has_finalizer (klass);
1889 if (mono_class_has_failure (klass)) {
1890 mono_domain_unlock (domain);
1891 mono_loader_unlock ();
1892 mono_error_set_for_class_failure (error, klass);
1896 vtable_slots = klass->vtable_size;
1897 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1898 class_size = mono_class_data_size (klass);
1902 if (klass->interface_offsets_count) {
1903 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1904 UnlockedIncrement (&mono_stats.imt_number_of_tables);
1905 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
1907 imt_table_bytes = 0;
1910 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1912 UnlockedIncrement (&mono_stats.used_class_count);
1913 UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
1915 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1916 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1917 g_assert (!((gsize)vt & 7));
1920 vt->rank = klass->rank;
1921 vt->domain = domain;
1923 mono_class_compute_gc_descriptor (klass);
1926 * We can't use typed allocation in the non-root domains, since the
1927 * collector needs the GC descriptor stored in the vtable even after
1928 * the mempool containing the vtable is destroyed when the domain is
1929 * unloaded. An alternative might be to allocate vtables in the GC
1930 * heap, but this does not seem to work (it leads to crashes inside
1931 * libgc). If that approach is tried, two gc descriptors need to be
1932 * allocated for each class: one for the root domain, and one for all
1933 * other domains. The second descriptor should contain a bit for the
1934 * vtable field in MonoObject, since we can no longer assume the
1935 * vtable is reachable by other roots after the appdomain is unloaded.
1937 if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1938 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1940 vt->gc_descr = klass->gc_descr;
1942 gc_bits = mono_gc_get_vtable_bits (klass);
1943 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1945 vt->gc_bits = gc_bits;
1948 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1949 if (klass->has_static_refs) {
1950 MonoGCDescriptor statics_gc_descr;
1952 gsize default_bitmap [4] = {0};
1955 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1956 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1957 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1958 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1959 if (bitmap != default_bitmap)
1962 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1964 vt->has_static_fields = TRUE;
1965 UnlockedAdd (&mono_stats.class_static_data_size, class_size);
1969 while ((field = mono_class_get_fields (klass, &iter))) {
1970 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1972 if (mono_field_is_deleted (field))
1974 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1975 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1976 if (special_static != SPECIAL_STATIC_NONE) {
1977 guint32 size, offset;
1979 gsize default_bitmap [4] = {0};
1984 if (mono_type_is_reference (field->type)) {
1985 default_bitmap [0] = 1;
1987 bitmap = default_bitmap;
1988 } else if (mono_type_is_struct (field->type)) {
1989 fclass = mono_class_from_mono_type (field->type);
1990 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1991 numbits = max_set + 1;
1993 default_bitmap [0] = 0;
1995 bitmap = default_bitmap;
1997 size = mono_type_size (field->type, &align);
1998 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1999 if (!domain->special_static_fields)
2000 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2001 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2002 if (bitmap != default_bitmap)
2005 * This marks the field as special static to speed up the
2006 * checks in mono_field_static_get/set_value ().
2012 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2013 MonoClass *fklass = mono_class_from_mono_type (field->type);
2014 const char *data = mono_field_get_data (field);
2016 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2017 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2018 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2021 if (fklass->valuetype) {
2022 memcpy (t, data, mono_class_value_size (fklass, NULL));
2024 /* it's a pointer type: add check */
2025 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2032 vt->max_interface_id = klass->max_interface_id;
2033 vt->interface_bitmap = klass->interface_bitmap;
2035 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2036 // class->name, klass->interface_offsets_count);
2038 /* Initialize vtable */
2039 if (callbacks.get_vtable_trampoline) {
2040 // This also covers the AOT case
2041 for (i = 0; i < klass->vtable_size; ++i) {
2042 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2045 mono_class_setup_vtable (klass);
2047 for (i = 0; i < klass->vtable_size; ++i) {
2050 cm = klass->vtable [i];
2052 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2053 if (!is_ok (error)) {
2054 mono_domain_unlock (domain);
2055 mono_loader_unlock ();
2062 if (imt_table_bytes) {
2063 /* Now that the vtable is full, we can actually fill up the IMT */
2064 for (i = 0; i < MONO_IMT_SIZE; ++i)
2065 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2069 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2070 * re-acquire them and check if another thread has created the vtable in the meantime.
2072 /* Special case System.MonoType to avoid infinite recursion */
2073 if (klass != mono_defaults.runtimetype_class) {
2074 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2075 if (!is_ok (error)) {
2076 mono_domain_unlock (domain);
2077 mono_loader_unlock ();
2081 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2082 /* This is unregistered in
2083 unregister_vtable_reflection_type() in
2085 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2088 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2090 /* class_vtable_array keeps an array of created vtables
2092 g_ptr_array_add (domain->class_vtable_array, vt);
2093 /* klass->runtime_info is protected by the loader lock, both when
2094 * it it enlarged and when it is stored info.
2098 * Store the vtable in klass->runtime_info.
2099 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2101 mono_memory_barrier ();
2103 old_info = klass->runtime_info;
2104 if (old_info && old_info->max_domain >= domain->domain_id) {
2105 /* someone already created a large enough runtime info */
2106 old_info->domain_vtables [domain->domain_id] = vt;
2108 int new_size = domain->domain_id;
2110 new_size = MAX (new_size, old_info->max_domain);
2112 /* make the new size a power of two */
2114 while (new_size > i)
2117 /* this is a bounded memory retention issue: may want to
2118 * handle it differently when we'll have a rcu-like system.
2120 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2121 runtime_info->max_domain = new_size - 1;
2122 /* copy the stuff from the older info */
2124 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2126 runtime_info->domain_vtables [domain->domain_id] = vt;
2128 mono_memory_barrier ();
2129 klass->runtime_info = runtime_info;
2132 if (klass == mono_defaults.runtimetype_class) {
2133 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2134 if (!is_ok (error)) {
2135 mono_domain_unlock (domain);
2136 mono_loader_unlock ();
2140 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2141 /* This is unregistered in
2142 unregister_vtable_reflection_type() in
2144 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2147 mono_domain_unlock (domain);
2148 mono_loader_unlock ();
2150 /* make sure the parent is initialized */
2151 /*FIXME shouldn't this fail the current type?*/
2153 mono_class_vtable_full (domain, klass->parent, error);
2158 #ifndef DISABLE_REMOTING
2160 * mono_remote_class_is_interface_proxy:
2161 * \param remote_class
2163 * Returns TRUE if the given remote class is a proxying an interface (as
2164 * opposed to a class deriving from MarshalByRefObject).
2167 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2169 /* This if condition is taking advantage of how mono_remote_class ()
2170 * works: if that code changes, this needs to change too. */
2171 return (remote_class->interface_count >= 1 &&
2172 remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2176 * mono_class_proxy_vtable:
2177 * \param domain the application domain
2178 * \param remove_class the remote class
2179 * \param error set on error
2180 * Creates a vtable for transparent proxies. It is basically
2181 * a copy of the real vtable of the class wrapped in \p remote_class,
2182 * but all function pointers invoke the remoting functions, and
2183 * \c vtable->klass points to the transparent proxy class, and not to \p class.
2185 * On failure returns NULL and sets \p error
2188 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2190 MONO_REQ_GC_UNSAFE_MODE;
2192 MonoVTable *vt, *pvt;
2193 int i, j, vtsize, extra_interface_vtsize = 0;
2194 guint32 max_interface_id;
2196 GSList *extra_interfaces = NULL;
2197 MonoClass *klass = remote_class->proxy_class;
2198 gpointer *interface_offsets;
2199 uint8_t *bitmap = NULL;
2201 size_t imt_table_bytes;
2203 #ifdef COMPRESSED_INTERFACE_BITMAP
2209 vt = mono_class_vtable (domain, klass);
2210 g_assert (vt); /*FIXME property handle failure*/
2211 max_interface_id = vt->max_interface_id;
2213 /* Calculate vtable space for extra interfaces */
2214 for (j = 0; j < remote_class->interface_count; j++) {
2215 MonoClass* iclass = remote_class->interfaces[j];
2219 /*FIXME test for interfaces with variant generic arguments*/
2220 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2221 continue; /* interface implemented by the class */
2222 if (g_slist_find (extra_interfaces, iclass))
2225 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2227 method_count = mono_class_num_methods (iclass);
2229 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2233 for (i = 0; i < ifaces->len; ++i) {
2234 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2235 /*FIXME test for interfaces with variant generic arguments*/
2236 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2237 continue; /* interface implemented by the class */
2238 if (g_slist_find (extra_interfaces, ic))
2240 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2241 method_count += mono_class_num_methods (ic);
2243 g_ptr_array_free (ifaces, TRUE);
2247 extra_interface_vtsize += method_count * sizeof (gpointer);
2248 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2251 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2252 UnlockedIncrement (&mono_stats.imt_number_of_tables);
2253 UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2255 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2257 UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2259 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2260 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2261 g_assert (!((gsize)pvt & 7));
2263 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2265 pvt->klass = mono_defaults.transparent_proxy_class;
2266 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2267 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2269 if (mono_remote_class_is_interface_proxy (remote_class)) {
2270 /* If it's a transparent proxy for an interface, set the
2271 * MonoVTable:type to the interface type, not the placeholder
2272 * MarshalByRefObject class. This is used when mini JITs calls
2273 * to Object.GetType ()
2275 MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
2276 pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2281 /* initialize vtable */
2282 mono_class_setup_vtable (klass);
2283 for (i = 0; i < klass->vtable_size; ++i) {
2286 if ((cm = klass->vtable [i])) {
2287 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2291 pvt->vtable [i] = NULL;
2294 if (mono_class_is_abstract (klass)) {
2295 /* create trampolines for abstract methods */
2296 for (k = klass; k; k = k->parent) {
2298 gpointer iter = NULL;
2299 while ((m = mono_class_get_methods (k, &iter)))
2300 if (!pvt->vtable [m->slot]) {
2301 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2308 pvt->max_interface_id = max_interface_id;
2309 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2310 #ifdef COMPRESSED_INTERFACE_BITMAP
2311 bitmap = (uint8_t *)g_malloc0 (bsize);
2313 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2316 for (i = 0; i < klass->interface_offsets_count; ++i) {
2317 int interface_id = klass->interfaces_packed [i]->interface_id;
2318 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2321 if (extra_interfaces) {
2322 int slot = klass->vtable_size;
2328 /* Create trampolines for the methods of the interfaces */
2329 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2330 interf = (MonoClass *)list_item->data;
2332 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2336 while ((cm = mono_class_get_methods (interf, &iter))) {
2337 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2342 slot += mono_class_num_methods (interf);
2346 /* Now that the vtable is full, we can actually fill up the IMT */
2347 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2348 if (extra_interfaces) {
2349 g_slist_free (extra_interfaces);
2352 #ifdef COMPRESSED_INTERFACE_BITMAP
2353 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2354 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2355 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2358 pvt->interface_bitmap = bitmap;
2362 if (extra_interfaces)
2363 g_slist_free (extra_interfaces);
2364 #ifdef COMPRESSED_INTERFACE_BITMAP
2370 #endif /* DISABLE_REMOTING */
2373 * mono_class_field_is_special_static:
2374 * \returns whether \p field is a thread/context static field.
2377 mono_class_field_is_special_static (MonoClassField *field)
2379 MONO_REQ_GC_NEUTRAL_MODE
2381 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2383 if (mono_field_is_deleted (field))
2385 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2386 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2393 * mono_class_field_get_special_static_type:
2394 * \param field The \c MonoClassField describing the field.
2395 * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2396 * \c SPECIAL_STATIC_NONE otherwise.
2399 mono_class_field_get_special_static_type (MonoClassField *field)
2401 MONO_REQ_GC_NEUTRAL_MODE
2403 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2404 return SPECIAL_STATIC_NONE;
2405 if (mono_field_is_deleted (field))
2406 return SPECIAL_STATIC_NONE;
2407 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2408 return field_is_special_static (field->parent, field);
2409 return SPECIAL_STATIC_NONE;
2413 * mono_class_has_special_static_fields:
2414 * \returns whether \p klass has any thread/context static fields.
2417 mono_class_has_special_static_fields (MonoClass *klass)
2419 MONO_REQ_GC_NEUTRAL_MODE
2421 MonoClassField *field;
2425 while ((field = mono_class_get_fields (klass, &iter))) {
2426 g_assert (field->parent == klass);
2427 if (mono_class_field_is_special_static (field))
2434 #ifndef DISABLE_REMOTING
2436 * create_remote_class_key:
2437 * Creates an array of pointers that can be used as a hash key for a remote class.
2438 * The first element of the array is the number of pointers.
2441 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2443 MONO_REQ_GC_NEUTRAL_MODE;
2448 if (remote_class == NULL) {
2449 if (mono_class_is_interface (extra_class)) {
2450 key = (void **)g_malloc (sizeof(gpointer) * 3);
2451 key [0] = GINT_TO_POINTER (2);
2452 key [1] = mono_defaults.marshalbyrefobject_class;
2453 key [2] = extra_class;
2455 key = (void **)g_malloc (sizeof(gpointer) * 2);
2456 key [0] = GINT_TO_POINTER (1);
2457 key [1] = extra_class;
2460 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2461 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2462 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2463 key [1] = remote_class->proxy_class;
2465 // Keep the list of interfaces sorted
2466 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2467 if (extra_class && remote_class->interfaces [i] > extra_class) {
2468 key [j++] = extra_class;
2471 key [j] = remote_class->interfaces [i];
2474 key [j] = extra_class;
2476 // Replace the old class. The interface list is the same
2477 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2478 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2479 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2480 for (i = 0; i < remote_class->interface_count; i++)
2481 key [2 + i] = remote_class->interfaces [i];
2489 * copy_remote_class_key:
2491 * Make a copy of KEY in the domain and return the copy.
2494 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2496 MONO_REQ_GC_NEUTRAL_MODE
2498 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2499 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2501 memcpy (mp_key, key, key_size);
2507 * mono_remote_class:
2508 * \param domain the application domain
2509 * \param class_name name of the remote class
2510 * \param error set on error
2511 * Creates and initializes a \c MonoRemoteClass object for a remote type.
2512 * On failure returns NULL and sets \p error
2515 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2517 MONO_REQ_GC_UNSAFE_MODE;
2519 MonoRemoteClass *rc;
2520 gpointer* key, *mp_key;
2525 key = create_remote_class_key (NULL, proxy_class);
2527 mono_domain_lock (domain);
2528 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2532 mono_domain_unlock (domain);
2536 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2537 if (!is_ok (error)) {
2539 mono_domain_unlock (domain);
2543 mp_key = copy_remote_class_key (domain, key);
2547 if (mono_class_is_interface (proxy_class)) {
2548 /* If we need to proxy an interface, we use this stylized
2549 * representation (interface_count >= 1, proxy_class is
2550 * MarshalByRefObject). The code in
2551 * mono_remote_class_is_interface_proxy () depends on being
2552 * able to detect that we're doing this, so if this
2553 * representation changes, change GetType, too. */
2554 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2555 rc->interface_count = 1;
2556 rc->interfaces [0] = proxy_class;
2557 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2559 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2560 rc->interface_count = 0;
2561 rc->proxy_class = proxy_class;
2564 rc->default_vtable = NULL;
2565 rc->xdomain_vtable = NULL;
2566 rc->proxy_class_name = name;
2567 #ifndef DISABLE_PERFCOUNTERS
2568 InterlockedAdd (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
2571 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2573 mono_domain_unlock (domain);
2578 * clone_remote_class:
2579 * Creates a copy of the remote_class, adding the provided class or interface
2581 static MonoRemoteClass*
2582 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2584 MONO_REQ_GC_NEUTRAL_MODE;
2586 MonoRemoteClass *rc;
2587 gpointer* key, *mp_key;
2589 key = create_remote_class_key (remote_class, extra_class);
2590 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2596 mp_key = copy_remote_class_key (domain, key);
2600 if (mono_class_is_interface (extra_class)) {
2602 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2603 rc->proxy_class = remote_class->proxy_class;
2604 rc->interface_count = remote_class->interface_count + 1;
2606 // Keep the list of interfaces sorted, since the hash key of
2607 // the remote class depends on this
2608 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2609 if (remote_class->interfaces [i] > extra_class && i == j)
2610 rc->interfaces [j++] = extra_class;
2611 rc->interfaces [j] = remote_class->interfaces [i];
2614 rc->interfaces [j] = extra_class;
2616 // Replace the old class. The interface array is the same
2617 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2618 rc->proxy_class = extra_class;
2619 rc->interface_count = remote_class->interface_count;
2620 if (rc->interface_count > 0)
2621 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2624 rc->default_vtable = NULL;
2625 rc->xdomain_vtable = NULL;
2626 rc->proxy_class_name = remote_class->proxy_class_name;
2628 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2634 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2636 MONO_REQ_GC_UNSAFE_MODE;
2640 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2641 mono_domain_lock (domain);
2642 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2643 if (target_domain_id != -1) {
2644 if (remote_class->xdomain_vtable == NULL)
2645 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2646 mono_domain_unlock (domain);
2647 mono_loader_unlock ();
2648 return_val_if_nok (error, NULL);
2649 return remote_class->xdomain_vtable;
2651 if (remote_class->default_vtable == NULL) {
2652 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2653 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2655 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2656 MonoClass *klass = mono_class_from_mono_type (type);
2658 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)))
2659 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2662 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2663 /* N.B. both branches of the if modify error */
2664 if (!is_ok (error)) {
2665 mono_domain_unlock (domain);
2666 mono_loader_unlock ();
2671 mono_domain_unlock (domain);
2672 mono_loader_unlock ();
2673 return remote_class->default_vtable;
2677 * mono_upgrade_remote_class:
2678 * \param domain the application domain
2679 * \param tproxy the proxy whose remote class has to be upgraded.
2680 * \param klass class to which the remote class can be casted.
2681 * \param error set on error
2682 * Updates the vtable of the remote class by adding the necessary method slots
2683 * and interface offsets so it can be safely casted to klass. klass can be a
2684 * class or an interface. On success returns TRUE, on failure returns FALSE and sets \p error.
2687 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2689 MONO_REQ_GC_UNSAFE_MODE;
2693 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2694 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2696 gboolean redo_vtable;
2697 if (mono_class_is_interface (klass)) {
2700 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2701 if (remote_class->interfaces [i] == klass)
2702 redo_vtable = FALSE;
2705 redo_vtable = (remote_class->proxy_class != klass);
2708 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2709 mono_domain_lock (domain);
2711 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2712 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2713 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2714 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2715 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2721 mono_domain_unlock (domain);
2722 mono_loader_unlock ();
2723 return is_ok (error);
2725 #endif /* DISABLE_REMOTING */
2729 * mono_object_get_virtual_method:
2730 * \param obj object to operate on.
2731 * \param method method
2732 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2733 * the instance of a callvirt of \p method.
2736 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2738 MONO_REQ_GC_UNSAFE_MODE;
2739 HANDLE_FUNCTION_ENTER ();
2741 MONO_HANDLE_DCL (MonoObject, obj);
2742 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2743 mono_error_assert_ok (&error);
2744 HANDLE_FUNCTION_RETURN_VAL (result);
2748 * mono_object_handle_get_virtual_method:
2749 * \param obj object to operate on.
2750 * \param method method
2751 * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2752 * the instance of a callvirt of \p method.
2755 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2759 gboolean is_proxy = FALSE;
2760 MonoClass *klass = mono_handle_class (obj);
2761 if (mono_class_is_transparent_proxy (klass)) {
2762 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2763 klass = remote_class->proxy_class;
2766 return class_get_virtual_method (klass, method, is_proxy, error);
2770 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2775 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2778 mono_class_setup_vtable (klass);
2779 MonoMethod **vtable = klass->vtable;
2781 if (method->slot == -1) {
2782 /* method->slot might not be set for instances of generic methods */
2783 if (method->is_inflated) {
2784 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2785 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2788 g_assert_not_reached ();
2792 MonoMethod *res = NULL;
2793 /* check method->slot is a valid index: perform isinstance? */
2794 if (method->slot != -1) {
2795 if (mono_class_is_interface (method->klass)) {
2797 gboolean variance_used = FALSE;
2798 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2799 g_assert (iface_offset > 0);
2800 res = vtable [iface_offset + method->slot];
2803 res = vtable [method->slot];
2807 #ifndef DISABLE_REMOTING
2809 /* It may be an interface, abstract class method or generic method */
2810 if (!res || mono_method_signature (res)->generic_param_count)
2813 /* generic methods demand invoke_with_check */
2814 if (mono_method_signature (res)->generic_param_count)
2815 res = mono_marshal_get_remoting_invoke_with_check (res);
2818 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2819 res = mono_cominterop_get_invoke (res);
2822 res = mono_marshal_get_remoting_invoke (res);
2827 if (method->is_inflated) {
2828 /* Have to inflate the result */
2829 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2837 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2839 MONO_REQ_GC_UNSAFE_MODE;
2841 MonoObject *result = NULL;
2843 g_assert (callbacks.runtime_invoke);
2847 MONO_PROFILER_RAISE (method_begin_invoke, (method));
2849 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2851 MONO_PROFILER_RAISE (method_end_invoke, (method));
2853 if (!mono_error_ok (error))
2860 * mono_runtime_invoke:
2861 * \param method method to invoke
2862 * \param obj object instance
2863 * \param params arguments to the method
2864 * \param exc exception information.
2865 * Invokes the method represented by \p method on the object \p obj.
2866 * \p obj is the \c this pointer, it should be NULL for static
2867 * methods, a \c MonoObject* for object instances and a pointer to
2868 * the value type for value types.
2870 * The params array contains the arguments to the method with the
2871 * same convention: \c MonoObject* pointers for object instances and
2872 * pointers to the value type otherwise.
2874 * From unmanaged code you'll usually use the
2875 * \c mono_runtime_invoke variant.
2877 * Note that this function doesn't handle virtual methods for
2878 * you, it will exec the exact method you pass: we still need to
2879 * expose a function to lookup the derived class implementation
2880 * of a virtual method (there are examples of this in the code,
2883 * You can pass NULL as the \p exc argument if you don't want to
2884 * catch exceptions, otherwise, \c *exc will be set to the exception
2885 * thrown, if any. if an exception is thrown, you can't use the
2886 * \c MonoObject* result from the function.
2888 * If the method returns a value type, it is boxed in an object
2892 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2897 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2898 if (*exc == NULL && !mono_error_ok(&error)) {
2899 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2901 mono_error_cleanup (&error);
2903 res = mono_runtime_invoke_checked (method, obj, params, &error);
2904 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2910 * mono_runtime_try_invoke:
2911 * \param method method to invoke
2912 * \param obj object instance
2913 * \param params arguments to the method
2914 * \param exc exception information.
2915 * \param error set on error
2916 * Invokes the method represented by \p method on the object \p obj.
2918 * \p obj is the \c this pointer, it should be NULL for static
2919 * methods, a \c MonoObject* for object instances and a pointer to
2920 * the value type for value types.
2922 * The params array contains the arguments to the method with the
2923 * same convention: \c MonoObject* pointers for object instances and
2924 * pointers to the value type otherwise.
2926 * From unmanaged code you'll usually use the
2927 * mono_runtime_invoke() variant.
2929 * Note that this function doesn't handle virtual methods for
2930 * you, it will exec the exact method you pass: we still need to
2931 * expose a function to lookup the derived class implementation
2932 * of a virtual method (there are examples of this in the code,
2935 * For this function, you must not pass NULL as the \p exc argument if
2936 * you don't want to catch exceptions, use
2937 * mono_runtime_invoke_checked(). If an exception is thrown, you
2938 * can't use the \c MonoObject* result from the function.
2940 * If this method cannot be invoked, \p error will be set and \p exc and
2941 * the return value must not be used.
2943 * If the method returns a value type, it is boxed in an object
2947 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2949 MONO_REQ_GC_UNSAFE_MODE;
2951 g_assert (exc != NULL);
2953 if (mono_runtime_get_no_exec ())
2954 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2956 return do_runtime_invoke (method, obj, params, exc, error);
2960 * mono_runtime_invoke_checked:
2961 * \param method method to invoke
2962 * \param obj object instance
2963 * \param params arguments to the method
2964 * \param error set on error
2965 * Invokes the method represented by \p method on the object \p obj.
2967 * \p obj is the \c this pointer, it should be NULL for static
2968 * methods, a \c MonoObject* for object instances and a pointer to
2969 * the value type for value types.
2971 * The \p params array contains the arguments to the method with the
2972 * same convention: \c MonoObject* pointers for object instances and
2973 * pointers to the value type otherwise.
2975 * From unmanaged code you'll usually use the
2976 * mono_runtime_invoke() variant.
2978 * Note that this function doesn't handle virtual methods for
2979 * you, it will exec the exact method you pass: we still need to
2980 * expose a function to lookup the derived class implementation
2981 * of a virtual method (there are examples of this in the code,
2984 * If an exception is thrown, you can't use the \c MonoObject* result
2985 * from the function.
2987 * If this method cannot be invoked, \p error will be set. If the
2988 * method throws an exception (and we're in coop mode) the exception
2989 * will be set in \p error.
2991 * If the method returns a value type, it is boxed in an object
2995 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2997 MONO_REQ_GC_UNSAFE_MODE;
2999 if (mono_runtime_get_no_exec ())
3000 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3002 return do_runtime_invoke (method, obj, params, NULL, error);
3006 * mono_method_get_unmanaged_thunk:
3007 * \param method method to generate a thunk for.
3009 * Returns an \c unmanaged->managed thunk that can be used to call
3010 * a managed method directly from C.
3012 * The thunk's C signature closely matches the managed signature:
3014 * C#: <code>public bool Equals (object obj);</code>
3016 * C: <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3018 * The 1st (<code>this</code>) parameter must not be used with static methods:
3020 * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3022 * C: <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3024 * The last argument must be a non-null \c MonoException* pointer.
3025 * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3026 * exception has been thrown in managed code. Otherwise it will point
3027 * to the \c MonoException* caught by the thunk. In this case, the result of
3028 * the thunk is undefined:
3031 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3033 * MonoException *ex = NULL;
3035 * Equals func = mono_method_get_unmanaged_thunk (method);
3037 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3041 * // handle exception
3046 * The calling convention of the thunk matches the platform's default
3047 * convention. This means that under Windows, C declarations must
3048 * contain the \c __stdcall attribute:
3050 * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3054 * Value type arguments and return values are treated as they were objects:
3056 * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3057 * C: <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3059 * Arguments must be properly boxed upon trunk's invocation, while return
3060 * values must be unboxed.
3063 mono_method_get_unmanaged_thunk (MonoMethod *method)
3065 MONO_REQ_GC_NEUTRAL_MODE;
3066 MONO_REQ_API_ENTRYPOINT;
3071 g_assert (!mono_threads_is_coop_enabled ());
3073 MONO_ENTER_GC_UNSAFE;
3074 method = mono_marshal_get_thunk_invoke_wrapper (method);
3075 res = mono_compile_method_checked (method, &error);
3076 mono_error_cleanup (&error);
3077 MONO_EXIT_GC_UNSAFE;
3083 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3085 MONO_REQ_GC_UNSAFE_MODE;
3089 /* object fields cannot be byref, so we don't need a
3091 gpointer *p = (gpointer*)dest;
3098 case MONO_TYPE_BOOLEAN:
3100 case MONO_TYPE_U1: {
3101 guint8 *p = (guint8*)dest;
3102 *p = value ? *(guint8*)value : 0;
3107 case MONO_TYPE_CHAR: {
3108 guint16 *p = (guint16*)dest;
3109 *p = value ? *(guint16*)value : 0;
3112 #if SIZEOF_VOID_P == 4
3117 case MONO_TYPE_U4: {
3118 gint32 *p = (gint32*)dest;
3119 *p = value ? *(gint32*)value : 0;
3122 #if SIZEOF_VOID_P == 8
3127 case MONO_TYPE_U8: {
3128 gint64 *p = (gint64*)dest;
3129 *p = value ? *(gint64*)value : 0;
3132 case MONO_TYPE_R4: {
3133 float *p = (float*)dest;
3134 *p = value ? *(float*)value : 0;
3137 case MONO_TYPE_R8: {
3138 double *p = (double*)dest;
3139 *p = value ? *(double*)value : 0;
3142 case MONO_TYPE_STRING:
3143 case MONO_TYPE_SZARRAY:
3144 case MONO_TYPE_CLASS:
3145 case MONO_TYPE_OBJECT:
3146 case MONO_TYPE_ARRAY:
3147 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3149 case MONO_TYPE_FNPTR:
3150 case MONO_TYPE_PTR: {
3151 gpointer *p = (gpointer*)dest;
3152 *p = deref_pointer? *(gpointer*)value: value;
3155 case MONO_TYPE_VALUETYPE:
3156 /* note that 't' and 'type->type' can be different */
3157 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3158 t = mono_class_enum_basetype (type->data.klass)->type;
3161 MonoClass *klass = mono_class_from_mono_type (type);
3162 int size = mono_class_value_size (klass, NULL);
3164 mono_gc_bzero_atomic (dest, size);
3166 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3169 case MONO_TYPE_GENERICINST:
3170 t = type->data.generic_class->container_class->byval_arg.type;
3173 g_error ("got type %x", type->type);
3178 * mono_field_set_value:
3179 * \param obj Instance object
3180 * \param field \c MonoClassField describing the field to set
3181 * \param value The value to be set
3183 * Sets the value of the field described by \p field in the object instance \p obj
3184 * to the value passed in \p value. This method should only be used for instance
3185 * fields. For static fields, use \c mono_field_static_set_value.
3187 * The value must be in the native format of the field type.
3190 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3192 MONO_REQ_GC_UNSAFE_MODE;
3196 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3198 dest = (char*)obj + field->offset;
3199 mono_copy_value (field->type, dest, value, FALSE);
3203 * mono_field_static_set_value:
3204 * \param field \c MonoClassField describing the field to set
3205 * \param value The value to be set
3206 * Sets the value of the static field described by \p field
3207 * to the value passed in \p value.
3208 * The value must be in the native format of the field type.
3211 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3213 MONO_REQ_GC_UNSAFE_MODE;
3217 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3218 /* you cant set a constant! */
3219 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3221 if (field->offset == -1) {
3222 /* Special static */
3225 mono_domain_lock (vt->domain);
3226 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3227 mono_domain_unlock (vt->domain);
3228 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3230 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3232 mono_copy_value (field->type, dest, value, FALSE);
3236 * mono_vtable_get_static_field_data:
3238 * Internal use function: return a pointer to the memory holding the static fields
3239 * for a class or NULL if there are no static fields.
3240 * This is exported only for use by the debugger.
3243 mono_vtable_get_static_field_data (MonoVTable *vt)
3245 MONO_REQ_GC_NEUTRAL_MODE
3247 if (!vt->has_static_fields)
3249 return vt->vtable [vt->klass->vtable_size];
3253 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3255 MONO_REQ_GC_UNSAFE_MODE;
3259 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3260 if (field->offset == -1) {
3261 /* Special static */
3264 mono_domain_lock (vt->domain);
3265 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3266 mono_domain_unlock (vt->domain);
3267 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3269 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3272 src = (guint8*)obj + field->offset;
3279 * mono_field_get_value:
3280 * \param obj Object instance
3281 * \param field \c MonoClassField describing the field to fetch information from
3282 * \param value pointer to the location where the value will be stored
3283 * Use this routine to get the value of the field \p field in the object
3286 * The pointer provided by value must be of the field type, for reference
3287 * types this is a \c MonoObject*, for value types its the actual pointer to
3295 * mono_field_get_value (obj, int_field, &i);
3299 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3301 MONO_REQ_GC_UNSAFE_MODE;
3307 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3309 src = (char*)obj + field->offset;
3310 mono_copy_value (field->type, value, src, TRUE);
3314 * mono_field_get_value_object:
3315 * \param domain domain where the object will be created (if boxing)
3316 * \param field \c MonoClassField describing the field to fetch information from
3317 * \param obj The object instance for the field.
3318 * \returns a new \c MonoObject with the value from the given field. If the
3319 * field represents a value type, the value is boxed.
3322 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3325 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3326 mono_error_assert_ok (&error);
3331 * mono_field_get_value_object_checked:
3332 * \param domain domain where the object will be created (if boxing)
3333 * \param field \c MonoClassField describing the field to fetch information from
3334 * \param obj The object instance for the field.
3335 * \param error Set on error.
3336 * \returns a new \c MonoObject with the value from the given field. If the
3337 * field represents a value type, the value is boxed. On error returns NULL and sets \p error.
3340 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3342 MONO_REQ_GC_UNSAFE_MODE;
3348 MonoVTable *vtable = NULL;
3350 gboolean is_static = FALSE;
3351 gboolean is_ref = FALSE;
3352 gboolean is_literal = FALSE;
3353 gboolean is_ptr = FALSE;
3354 MonoType *type = mono_field_get_type_checked (field, error);
3356 return_val_if_nok (error, NULL);
3358 switch (type->type) {
3359 case MONO_TYPE_STRING:
3360 case MONO_TYPE_OBJECT:
3361 case MONO_TYPE_CLASS:
3362 case MONO_TYPE_ARRAY:
3363 case MONO_TYPE_SZARRAY:
3368 case MONO_TYPE_BOOLEAN:
3371 case MONO_TYPE_CHAR:
3380 case MONO_TYPE_VALUETYPE:
3381 is_ref = type->byref;
3383 case MONO_TYPE_GENERICINST:
3384 is_ref = !mono_type_generic_inst_is_valuetype (type);
3390 g_error ("type 0x%x not handled in "
3391 "mono_field_get_value_object", type->type);
3395 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3398 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3402 vtable = mono_class_vtable_full (domain, field->parent, error);
3403 return_val_if_nok (error, NULL);
3405 if (!vtable->initialized) {
3406 mono_runtime_class_init_full (vtable, error);
3407 return_val_if_nok (error, NULL);
3416 get_default_field_value (domain, field, &o, error);
3417 return_val_if_nok (error, NULL);
3418 } else if (is_static) {
3419 mono_field_static_get_value_checked (vtable, field, &o, error);
3420 return_val_if_nok (error, NULL);
3422 mono_field_get_value (obj, field, &o);
3428 static MonoMethod *m;
3434 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3435 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3441 get_default_field_value (domain, field, v, error);
3442 return_val_if_nok (error, NULL);
3443 } else if (is_static) {
3444 mono_field_static_get_value_checked (vtable, field, v, error);
3445 return_val_if_nok (error, NULL);
3447 mono_field_get_value (obj, field, v);
3450 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3451 args [0] = ptr ? *ptr : NULL;
3452 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3453 return_val_if_nok (error, NULL);
3455 o = mono_runtime_invoke_checked (m, NULL, args, error);
3456 return_val_if_nok (error, NULL);
3461 /* boxed value type */
3462 klass = mono_class_from_mono_type (type);
3464 if (mono_class_is_nullable (klass))
3465 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3467 o = mono_object_new_checked (domain, klass, error);
3468 return_val_if_nok (error, NULL);
3469 v = ((gchar *) o) + sizeof (MonoObject);
3472 get_default_field_value (domain, field, v, error);
3473 return_val_if_nok (error, NULL);
3474 } else if (is_static) {
3475 mono_field_static_get_value_checked (vtable, field, v, error);
3476 return_val_if_nok (error, NULL);
3478 mono_field_get_value (obj, field, v);
3485 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3487 MONO_REQ_GC_UNSAFE_MODE;
3491 const char *p = blob;
3492 mono_metadata_decode_blob_size (p, &p);
3495 case MONO_TYPE_BOOLEAN:
3498 *(guint8 *) value = *p;
3500 case MONO_TYPE_CHAR:
3503 *(guint16*) value = read16 (p);
3507 *(guint32*) value = read32 (p);
3511 *(guint64*) value = read64 (p);
3514 readr4 (p, (float*) value);
3517 readr8 (p, (double*) value);
3519 case MONO_TYPE_STRING:
3520 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3522 case MONO_TYPE_CLASS:
3523 *(gpointer*) value = NULL;
3527 g_warning ("type 0x%02x should not be in constant table", type);
3533 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3535 MONO_REQ_GC_NEUTRAL_MODE;
3537 MonoTypeEnum def_type;
3542 data = mono_class_get_field_default_value (field, &def_type);
3543 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3547 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3549 MONO_REQ_GC_UNSAFE_MODE;
3555 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3557 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3558 get_default_field_value (vt->domain, field, value, error);
3562 if (field->offset == -1) {
3563 /* Special static */
3564 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3565 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3567 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3569 mono_copy_value (field->type, value, src, TRUE);
3573 * mono_field_static_get_value:
3574 * \param vt vtable to the object
3575 * \param field \c MonoClassField describing the field to fetch information from
3576 * \param value where the value is returned
3577 * Use this routine to get the value of the static field \p field value.
3579 * The pointer provided by value must be of the field type, for reference
3580 * types this is a \c MonoObject*, for value types its the actual pointer to
3588 * mono_field_static_get_value (vt, int_field, &i);
3592 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3594 MONO_REQ_GC_NEUTRAL_MODE;
3597 mono_field_static_get_value_checked (vt, field, value, &error);
3598 mono_error_cleanup (&error);
3602 * mono_field_static_get_value_checked:
3603 * \param vt vtable to the object
3604 * \param field \c MonoClassField describing the field to fetch information from
3605 * \param value where the value is returned
3606 * \param error set on error
3607 * Use this routine to get the value of the static field \p field value.
3609 * The pointer provided by value must be of the field type, for reference
3610 * types this is a \c MonoObject*, for value types its the actual pointer to
3615 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3616 * if (!is_ok (error)) { ... }
3618 * On failure sets \p error.
3621 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3623 MONO_REQ_GC_NEUTRAL_MODE;
3625 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3629 * mono_property_set_value:
3630 * \param prop MonoProperty to set
3631 * \param obj instance object on which to act
3632 * \param params parameters to pass to the propery
3633 * \param exc optional exception
3634 * Invokes the property's set method with the given arguments on the
3635 * object instance obj (or NULL for static properties).
3637 * You can pass NULL as the exc argument if you don't want to
3638 * catch exceptions, otherwise, \c *exc will be set to the exception
3639 * thrown, if any. if an exception is thrown, you can't use the
3640 * \c MonoObject* result from the function.
3643 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3645 MONO_REQ_GC_UNSAFE_MODE;
3648 do_runtime_invoke (prop->set, obj, params, exc, &error);
3649 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3650 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3652 mono_error_cleanup (&error);
3657 * mono_property_set_value_checked:
3658 * \param prop \c MonoProperty to set
3659 * \param obj instance object on which to act
3660 * \param params parameters to pass to the propery
3661 * \param error set on error
3662 * Invokes the property's set method with the given arguments on the
3663 * object instance \p obj (or NULL for static properties).
3664 * \returns TRUE on success. On failure returns FALSE and sets \p error.
3665 * If an exception is thrown, it will be caught and returned via \p error.
3668 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3670 MONO_REQ_GC_UNSAFE_MODE;
3675 do_runtime_invoke (prop->set, obj, params, &exc, error);
3676 if (exc != NULL && is_ok (error))
3677 mono_error_set_exception_instance (error, (MonoException*)exc);
3678 return is_ok (error);
3682 * mono_property_get_value:
3683 * \param prop \c MonoProperty to fetch
3684 * \param obj instance object on which to act
3685 * \param params parameters to pass to the propery
3686 * \param exc optional exception
3687 * Invokes the property's \c get method with the given arguments on the
3688 * object instance \p obj (or NULL for static properties).
3690 * You can pass NULL as the \p exc argument if you don't want to
3691 * catch exceptions, otherwise, \c *exc will be set to the exception
3692 * thrown, if any. if an exception is thrown, you can't use the
3693 * \c MonoObject* result from the function.
3695 * \returns the value from invoking the \c get method on the property.
3698 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3700 MONO_REQ_GC_UNSAFE_MODE;
3703 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3704 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3705 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3707 mono_error_cleanup (&error); /* FIXME don't raise here */
3714 * mono_property_get_value_checked:
3715 * \param prop \c MonoProperty to fetch
3716 * \param obj instance object on which to act
3717 * \param params parameters to pass to the propery
3718 * \param error set on error
3719 * Invokes the property's \c get method with the given arguments on the
3720 * object instance obj (or NULL for static properties).
3722 * If an exception is thrown, you can't use the
3723 * \c MonoObject* result from the function. The exception will be propagated via \p error.
3725 * \returns the value from invoking the get method on the property. On
3726 * failure returns NULL and sets \p error.
3729 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3731 MONO_REQ_GC_UNSAFE_MODE;
3734 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3735 if (exc != NULL && !is_ok (error))
3736 mono_error_set_exception_instance (error, (MonoException*) exc);
3744 * mono_nullable_init:
3745 * @buf: The nullable structure to initialize.
3746 * @value: the value to initialize from
3747 * @klass: the type for the object
3749 * Initialize the nullable structure pointed to by @buf from @value which
3750 * should be a boxed value type. The size of @buf should be able to hold
3751 * as much data as the @klass->instance_size (which is the number of bytes
3752 * that will be copies).
3754 * Since Nullables have variable structure, we can not define a C
3755 * structure for them.
3758 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3760 MONO_REQ_GC_UNSAFE_MODE;
3762 MonoClass *param_class = klass->cast_class;
3764 mono_class_setup_fields (klass);
3765 g_assert (klass->fields_inited);
3767 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3768 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3770 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3772 if (param_class->has_references)
3773 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3775 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3777 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3782 * mono_nullable_init_from_handle:
3783 * @buf: The nullable structure to initialize.
3784 * @value: the value to initialize from
3785 * @klass: the type for the object
3787 * Initialize the nullable structure pointed to by @buf from @value which
3788 * should be a boxed value type. The size of @buf should be able to hold
3789 * as much data as the @klass->instance_size (which is the number of bytes
3790 * that will be copies).
3792 * Since Nullables have variable structure, we can not define a C
3793 * structure for them.
3796 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3798 MONO_REQ_GC_UNSAFE_MODE;
3800 MonoClass *param_class = klass->cast_class;
3802 mono_class_setup_fields (klass);
3803 g_assert (klass->fields_inited);
3805 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3806 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3808 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL (value) ? 0 : 1;
3809 if (!MONO_HANDLE_IS_NULL (value)) {
3810 uint32_t value_gchandle = 0;
3811 gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3812 if (param_class->has_references)
3813 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3815 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3816 mono_gchandle_free (value_gchandle);
3818 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3825 * mono_nullable_box:
3826 * \param buf The buffer representing the data to be boxed
3827 * \param klass the type to box it as.
3828 * \param error set on error
3830 * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3831 * \p buf. On failure returns NULL and sets \p error.
3834 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3836 MONO_REQ_GC_UNSAFE_MODE;
3839 MonoClass *param_class = klass->cast_class;
3841 mono_class_setup_fields (klass);
3842 g_assert (klass->fields_inited);
3844 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3845 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3847 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3848 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3849 return_val_if_nok (error, NULL);
3850 if (param_class->has_references)
3851 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3853 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3861 * mono_get_delegate_invoke:
3862 * \param klass The delegate class
3863 * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3866 mono_get_delegate_invoke (MonoClass *klass)
3868 MONO_REQ_GC_NEUTRAL_MODE;
3872 /* This is called at runtime, so avoid the slower search in metadata */
3873 mono_class_setup_methods (klass);
3874 if (mono_class_has_failure (klass))
3876 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3881 * mono_get_delegate_begin_invoke:
3882 * \param klass The delegate class
3883 * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3886 mono_get_delegate_begin_invoke (MonoClass *klass)
3888 MONO_REQ_GC_NEUTRAL_MODE;
3892 /* This is called at runtime, so avoid the slower search in metadata */
3893 mono_class_setup_methods (klass);
3894 if (mono_class_has_failure (klass))
3896 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3901 * mono_get_delegate_end_invoke:
3902 * \param klass The delegate class
3903 * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3906 mono_get_delegate_end_invoke (MonoClass *klass)
3908 MONO_REQ_GC_NEUTRAL_MODE;
3912 /* This is called at runtime, so avoid the slower search in metadata */
3913 mono_class_setup_methods (klass);
3914 if (mono_class_has_failure (klass))
3916 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3921 * mono_runtime_delegate_invoke:
3922 * \param delegate pointer to a delegate object.
3923 * \param params parameters for the delegate.
3924 * \param exc Pointer to the exception result.
3926 * Invokes the delegate method \p delegate with the parameters provided.
3928 * You can pass NULL as the \p exc argument if you don't want to
3929 * catch exceptions, otherwise, \c *exc will be set to the exception
3930 * thrown, if any. if an exception is thrown, you can't use the
3931 * \c MonoObject* result from the function.
3934 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3936 MONO_REQ_GC_UNSAFE_MODE;
3940 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3942 mono_error_cleanup (&error);
3945 if (!is_ok (&error))
3946 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3950 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3951 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3957 * mono_runtime_delegate_try_invoke:
3958 * \param delegate pointer to a delegate object.
3959 * \param params parameters for the delegate.
3960 * \param exc Pointer to the exception result.
3961 * \param error set on error
3962 * Invokes the delegate method \p delegate with the parameters provided.
3964 * You can pass NULL as the \p exc argument if you don't want to
3965 * catch exceptions, otherwise, \c *exc will be set to the exception
3966 * thrown, if any. On failure to execute, \p error will be set.
3967 * if an exception is thrown, you can't use the
3968 * \c MonoObject* result from the function.
3971 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3973 MONO_REQ_GC_UNSAFE_MODE;
3977 MonoClass *klass = delegate->vtable->klass;
3980 im = mono_get_delegate_invoke (klass);
3982 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3985 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3987 o = mono_runtime_invoke_checked (im, delegate, params, error);
3994 * mono_runtime_delegate_invoke_checked:
3995 * \param delegate pointer to a delegate object.
3996 * \param params parameters for the delegate.
3997 * \param error set on error
3998 * Invokes the delegate method \p delegate with the parameters provided.
3999 * On failure \p error will be set and you can't use the \c MonoObject*
4000 * result from the function.
4003 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4006 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4009 static char **main_args = NULL;
4010 static int num_main_args = 0;
4013 * mono_runtime_get_main_args:
4014 * \returns A \c MonoArray with the arguments passed to the main program
4017 mono_runtime_get_main_args (void)
4019 MONO_REQ_GC_UNSAFE_MODE;
4021 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4022 mono_error_assert_ok (&error);
4027 * mono_runtime_get_main_args_checked:
4028 * \param error set on error
4029 * \returns a \c MonoArray with the arguments passed to the main
4030 * program. On failure returns NULL and sets \p error.
4033 mono_runtime_get_main_args_checked (MonoError *error)
4037 MonoDomain *domain = mono_domain_get ();
4041 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4042 return_val_if_nok (error, NULL);
4044 for (i = 0; i < num_main_args; ++i) {
4045 MonoString *arg = mono_string_new_checked (domain, main_args [i], error);
4046 return_val_if_nok (error, NULL);
4047 mono_array_setref (res, i, arg);
4054 free_main_args (void)
4056 MONO_REQ_GC_NEUTRAL_MODE;
4060 for (i = 0; i < num_main_args; ++i)
4061 g_free (main_args [i]);
4068 * mono_runtime_set_main_args:
4069 * \param argc number of arguments from the command line
4070 * \param argv array of strings from the command line
4071 * Set the command line arguments from an embedding application that doesn't otherwise call
4072 * \c mono_runtime_run_main.
4075 mono_runtime_set_main_args (int argc, char* argv[])
4077 MONO_REQ_GC_NEUTRAL_MODE;
4082 main_args = g_new0 (char*, argc);
4083 num_main_args = argc;
4085 for (i = 0; i < argc; ++i) {
4088 utf8_arg = mono_utf8_from_external (argv[i]);
4089 if (utf8_arg == NULL) {
4090 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4091 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4095 main_args [i] = utf8_arg;
4102 * Prepare an array of arguments in order to execute a standard Main()
4103 * method (argc/argv contains the executable name). This method also
4104 * sets the command line argument value needed by System.Environment.
4108 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4110 MONO_REQ_GC_UNSAFE_MODE;
4114 MonoArray *args = NULL;
4115 MonoDomain *domain = mono_domain_get ();
4116 gchar *utf8_fullpath;
4117 MonoMethodSignature *sig;
4119 g_assert (method != NULL);
4121 mono_thread_set_main (mono_thread_current ());
4123 main_args = g_new0 (char*, argc);
4124 num_main_args = argc;
4126 if (!g_path_is_absolute (argv [0])) {
4127 gchar *basename = g_path_get_basename (argv [0]);
4128 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4132 utf8_fullpath = mono_utf8_from_external (fullpath);
4133 if(utf8_fullpath == NULL) {
4134 /* Printing the arg text will cause glib to
4135 * whinge about "Invalid UTF-8", but at least
4136 * its relevant, and shows the problem text
4139 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4140 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4147 utf8_fullpath = mono_utf8_from_external (argv[0]);
4148 if(utf8_fullpath == NULL) {
4149 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4150 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4155 main_args [0] = utf8_fullpath;
4157 for (i = 1; i < argc; ++i) {
4160 utf8_arg=mono_utf8_from_external (argv[i]);
4161 if(utf8_arg==NULL) {
4162 /* Ditto the comment about Invalid UTF-8 here */
4163 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4164 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4168 main_args [i] = utf8_arg;
4173 sig = mono_method_signature (method);
4175 g_print ("Unable to load Main method.\n");
4179 if (sig->param_count) {
4180 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4181 mono_error_assert_ok (&error);
4182 for (i = 0; i < argc; ++i) {
4183 /* The encodings should all work, given that
4184 * we've checked all these args for the
4187 gchar *str = mono_utf8_from_external (argv [i]);
4188 MonoString *arg = mono_string_new_checked (domain, str, &error);
4189 mono_error_assert_ok (&error);
4190 mono_array_setref (args, i, arg);
4194 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4195 mono_error_assert_ok (&error);
4198 mono_assembly_set_main (method->klass->image->assembly);
4204 * mono_runtime_run_main:
4205 * \param method the method to start the application with (usually <code>Main</code>)
4206 * \param argc number of arguments from the command line
4207 * \param argv array of strings from the command line
4208 * \param exc excetption results
4209 * Execute a standard \c Main method (\p argc / \p argv contains the
4210 * executable name). This method also sets the command line argument value
4211 * needed by \c System.Environment.
4214 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4217 MONO_REQ_GC_UNSAFE_MODE;
4220 MonoArray *args = prepare_run_main (method, argc, argv);
4223 res = mono_runtime_try_exec_main (method, args, exc);
4225 res = mono_runtime_exec_main_checked (method, args, &error);
4226 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4232 * mono_runtime_run_main_checked:
4233 * \param method the method to start the application with (usually \c Main)
4234 * \param argc number of arguments from the command line
4235 * \param argv array of strings from the command line
4236 * \param error set on error
4238 * Execute a standard \c Main method (\p argc / \p argv contains the
4239 * executable name). This method also sets the command line argument value
4240 * needed by \c System.Environment. On failure sets \p error.
4243 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4247 MonoArray *args = prepare_run_main (method, argc, argv);
4248 return mono_runtime_exec_main_checked (method, args, error);
4252 * mono_runtime_try_run_main:
4253 * \param method the method to start the application with (usually \c Main)
4254 * \param argc number of arguments from the command line
4255 * \param argv array of strings from the command line
4256 * \param exc set if \c Main throws an exception
4257 * \param error set if \c Main can't be executed
4258 * Execute a standard \c Main method (\p argc / \p argv contains the executable
4259 * name). This method also sets the command line argument value needed
4260 * by \c System.Environment. On failure sets \p error if Main can't be
4261 * executed or \p exc if it threw an exception.
4264 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4268 MonoArray *args = prepare_run_main (method, argc, argv);
4269 return mono_runtime_try_exec_main (method, args, exc);
4274 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4276 static MonoMethod *serialize_method;
4282 if (!serialize_method) {
4283 MonoClass *klass = mono_class_get_remoting_services_class ();
4284 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4287 if (!serialize_method) {
4292 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4297 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4298 if (*exc == NULL && !mono_error_ok (&error))
4299 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4301 mono_error_cleanup (&error);
4310 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4312 MONO_REQ_GC_UNSAFE_MODE;
4314 static MonoMethod *deserialize_method;
4320 if (!deserialize_method) {
4321 MonoClass *klass = mono_class_get_remoting_services_class ();
4322 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4324 if (!deserialize_method) {
4332 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4333 if (*exc == NULL && !mono_error_ok (&error))
4334 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4336 mono_error_cleanup (&error);
4344 #ifndef DISABLE_REMOTING
4346 make_transparent_proxy (MonoObject *obj, MonoError *error)
4348 MONO_REQ_GC_UNSAFE_MODE;
4350 static MonoMethod *get_proxy_method;
4352 MonoDomain *domain = mono_domain_get ();
4353 MonoRealProxy *real_proxy;
4354 MonoReflectionType *reflection_type;
4355 MonoTransparentProxy *transparent_proxy;
4359 if (!get_proxy_method)
4360 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4362 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4364 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4365 return_val_if_nok (error, NULL);
4366 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4367 return_val_if_nok (error, NULL);
4369 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4370 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4372 MonoObject *exc = NULL;
4374 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4375 if (exc != NULL && is_ok (error))
4376 mono_error_set_exception_instance (error, (MonoException*)exc);
4378 return (MonoObject*) transparent_proxy;
4380 #endif /* DISABLE_REMOTING */
4383 * mono_object_xdomain_representation
4384 * \param obj an object
4385 * \param target_domain a domain
4386 * \param error set on error.
4387 * Creates a representation of obj in the domain \p target_domain. This
4388 * is either a copy of \p obj arrived through via serialization and
4389 * deserialization or a proxy, depending on whether the object is
4390 * serializable or marshal by ref. \p obj must not be in \p target_domain.
4391 * If the object cannot be represented in \p target_domain, NULL is
4392 * returned and \p error is set appropriately.
4395 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4397 MONO_REQ_GC_UNSAFE_MODE;
4400 MonoObject *deserialized = NULL;
4402 #ifndef DISABLE_REMOTING
4403 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4404 deserialized = make_transparent_proxy (obj, error);
4409 gboolean failure = FALSE;
4410 MonoDomain *domain = mono_domain_get ();
4411 MonoObject *serialized;
4412 MonoObject *exc = NULL;
4414 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4415 serialized = serialize_object (obj, &failure, &exc);
4416 mono_domain_set_internal_with_options (target_domain, FALSE);
4418 deserialized = deserialize_object (serialized, &failure, &exc);
4419 if (domain != target_domain)
4420 mono_domain_set_internal_with_options (domain, FALSE);
4422 mono_error_set_exception_instance (error, (MonoException*)exc);
4425 return deserialized;
4428 /* Used in call_unhandled_exception_delegate */
4430 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4432 MONO_REQ_GC_UNSAFE_MODE;
4437 MonoMethod *method = NULL;
4438 MonoBoolean is_terminating = TRUE;
4441 klass = mono_class_get_unhandled_exception_event_args_class ();
4442 mono_class_init (klass);
4444 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4445 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4449 args [1] = &is_terminating;
4451 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4452 return_val_if_nok (error, NULL);
4454 mono_runtime_invoke_checked (method, obj, args, error);
4455 return_val_if_nok (error, NULL);
4460 /* Used in mono_unhandled_exception */
4462 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4463 MONO_REQ_GC_UNSAFE_MODE;
4466 MonoObject *e = NULL;
4468 MonoDomain *current_domain = mono_domain_get ();
4470 if (domain != current_domain)
4471 mono_domain_set_internal_with_options (domain, FALSE);
4473 g_assert (domain == mono_object_domain (domain->domain));
4475 if (mono_object_domain (exc) != domain) {
4477 exc = mono_object_xdomain_representation (exc, domain, &error);
4479 if (!is_ok (&error)) {
4480 MonoError inner_error;
4481 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4482 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4483 mono_error_assert_ok (&inner_error);
4485 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4486 "System.Runtime.Serialization", "SerializationException",
4487 "Could not serialize unhandled exception.");
4491 g_assert (mono_object_domain (exc) == domain);
4493 pa [0] = domain->domain;
4494 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4495 mono_error_assert_ok (&error);
4496 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4497 if (!is_ok (&error)) {
4499 e = (MonoObject*)mono_error_convert_to_exception (&error);
4501 mono_error_cleanup (&error);
4504 if (domain != current_domain)
4505 mono_domain_set_internal_with_options (current_domain, FALSE);
4508 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4509 if (!mono_error_ok (&error)) {
4510 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4511 mono_error_cleanup (&error);
4513 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4519 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4522 * mono_runtime_unhandled_exception_policy_set:
4523 * \param policy the new policy
4524 * This is a VM internal routine.
4525 * Sets the runtime policy for handling unhandled exceptions.
4528 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4529 runtime_unhandled_exception_policy = policy;
4533 * mono_runtime_unhandled_exception_policy_get:
4535 * This is a VM internal routine.
4537 * Gets the runtime policy for handling unhandled exceptions.
4539 MonoRuntimeUnhandledExceptionPolicy
4540 mono_runtime_unhandled_exception_policy_get (void) {
4541 return runtime_unhandled_exception_policy;
4545 * mono_unhandled_exception:
4546 * \param exc exception thrown
4547 * This is a VM internal routine.
4549 * We call this function when we detect an unhandled exception
4550 * in the default domain.
4552 * It invokes the \c UnhandledException event in \c AppDomain or prints
4553 * a warning to the console
4556 mono_unhandled_exception (MonoObject *exc_raw)
4559 HANDLE_FUNCTION_ENTER ();
4560 MONO_HANDLE_DCL (MonoObject, exc);
4561 error_init (&error);
4562 mono_unhandled_exception_checked (exc, &error);
4563 mono_error_assert_ok (&error);
4564 HANDLE_FUNCTION_RETURN ();
4568 * mono_unhandled_exception:
4569 * @exc: exception thrown
4571 * This is a VM internal routine.
4573 * We call this function when we detect an unhandled exception
4574 * in the default domain.
4576 * It invokes the * UnhandledException event in AppDomain or prints
4577 * a warning to the console
4580 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4582 MONO_REQ_GC_UNSAFE_MODE;
4585 MonoClassField *field;
4586 MonoDomain *current_domain, *root_domain;
4587 MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4589 MonoClass *klass = mono_handle_class (exc);
4591 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
4592 * a thread started in unmanaged world.
4593 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
4595 if (klass == mono_defaults.threadabortexception_class ||
4596 (klass == mono_class_get_appdomain_unloaded_exception_class () &&
4597 mono_thread_info_current ()->runtime_thread))
4600 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4603 current_domain = mono_domain_get ();
4604 root_domain = mono_get_root_domain ();
4606 MonoObjectHandle root_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, error)); /* FIXME use handles for mono_field_get_value_object_checked */
4607 return_if_nok (error);
4608 if (current_domain != root_domain) {
4609 MONO_HANDLE_ASSIGN (current_appdomain_delegate, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, error))); /* FIXME use handles for mono_field_get_value_object_checked */
4610 return_if_nok (error);
4613 if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4614 mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4616 /* unhandled exception callbacks must not be aborted */
4617 mono_threads_begin_abort_protected_block ();
4618 if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4619 call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4620 if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4621 call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4622 mono_threads_end_abort_protected_block ();
4625 /* set exitcode only if we will abort the process */
4626 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4627 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4629 mono_environment_exitcode_set (1);
4634 * mono_runtime_exec_managed_code:
4635 * \param domain Application domain
4636 * \param main_func function to invoke from the execution thread
4637 * \param main_args parameter to the main_func
4638 * Launch a new thread to execute a function
4640 * \p main_func is called back from the thread with main_args as the
4641 * parameter. The callback function is expected to start \c Main
4642 * eventually. This function then waits for all managed threads to
4644 * It is not necessary anymore to execute managed code in a subthread,
4645 * so this function should not be used anymore by default: just
4646 * execute the code and then call mono_thread_manage().
4649 mono_runtime_exec_managed_code (MonoDomain *domain,
4650 MonoMainThreadFunc main_func,
4654 mono_thread_create_checked (domain, main_func, main_args, &error);
4655 mono_error_assert_ok (&error);
4657 mono_thread_manage ();
4661 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4663 MonoInternalThread* thread = mono_thread_internal_current ();
4664 MonoCustomAttrInfo* cinfo;
4665 gboolean has_stathread_attribute;
4667 if (!domain->entry_assembly) {
4670 MonoAssembly *assembly;
4672 assembly = method->klass->image->assembly;
4673 domain->entry_assembly = assembly;
4674 /* Domains created from another domain already have application_base and configuration_file set */
4675 if (domain->setup->application_base == NULL) {
4676 MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4677 mono_error_assert_ok (&error);
4678 MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4681 if (domain->setup->configuration_file == NULL) {
4682 str = g_strconcat (assembly->image->name, ".config", NULL);
4683 MonoString *config_file = mono_string_new_checked (domain, str, &error);
4684 mono_error_assert_ok (&error);
4685 MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4687 mono_domain_set_options_from_config (domain);
4691 MonoError cattr_error;
4692 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4693 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4695 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4697 mono_custom_attrs_free (cinfo);
4699 has_stathread_attribute = FALSE;
4701 if (has_stathread_attribute) {
4702 thread->apartment_state = ThreadApartmentState_STA;
4704 thread->apartment_state = ThreadApartmentState_MTA;
4706 mono_thread_init_apartment_state ();
4711 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4713 MONO_REQ_GC_UNSAFE_MODE;
4723 /* FIXME: check signature of method */
4724 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4726 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4728 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4731 mono_environment_exitcode_set (rval);
4733 mono_runtime_invoke_checked (method, NULL, pa, error);
4745 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4747 MONO_REQ_GC_UNSAFE_MODE;
4757 /* FIXME: check signature of method */
4758 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4759 MonoError inner_error;
4761 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4762 if (*exc == NULL && !mono_error_ok (&inner_error))
4763 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4765 mono_error_cleanup (&inner_error);
4768 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4772 mono_environment_exitcode_set (rval);
4774 MonoError inner_error;
4775 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4776 if (*exc == NULL && !mono_error_ok (&inner_error))
4777 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4779 mono_error_cleanup (&inner_error);
4784 /* If the return type of Main is void, only
4785 * set the exitcode if an exception was thrown
4786 * (we don't want to blow away an
4787 * explicitly-set exit code)
4790 mono_environment_exitcode_set (rval);
4798 * Execute a standard Main() method (args doesn't contain the
4802 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4805 prepare_thread_to_exec_main (mono_object_domain (args), method);
4807 int rval = do_try_exec_main (method, args, exc);
4810 int rval = do_exec_main_checked (method, args, &error);
4811 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4817 * Execute a standard Main() method (args doesn't contain the
4820 * On failure sets @error
4823 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4826 prepare_thread_to_exec_main (mono_object_domain (args), method);
4827 return do_exec_main_checked (method, args, error);
4831 * Execute a standard Main() method (args doesn't contain the
4834 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4837 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4839 prepare_thread_to_exec_main (mono_object_domain (args), method);
4840 return do_try_exec_main (method, args, exc);
4845 /** invoke_array_extract_argument:
4846 * @params: array of arguments to the method.
4847 * @i: the index of the argument to extract.
4848 * @t: ith type from the method signature.
4849 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4850 * @error: set on error.
4852 * Given an array of method arguments, return the ith one using the corresponding type
4853 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4855 * On failure sets @error and returns NULL.
4858 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4860 MonoType *t_orig = t;
4861 gpointer result = NULL;
4867 case MONO_TYPE_BOOLEAN:
4870 case MONO_TYPE_CHAR:
4879 case MONO_TYPE_VALUETYPE:
4880 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4881 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4882 result = mono_array_get (params, MonoObject*, i);
4884 *has_byref_nullables = TRUE;
4886 /* MS seems to create the objects if a null is passed in */
4887 gboolean was_null = FALSE;
4888 if (!mono_array_get (params, MonoObject*, i)) {
4889 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4890 return_val_if_nok (error, NULL);
4891 mono_array_setref (params, i, o);
4897 * We can't pass the unboxed vtype byref to the callee, since
4898 * that would mean the callee would be able to modify boxed
4899 * primitive types. So we (and MS) make a copy of the boxed
4900 * object, pass that to the callee, and replace the original
4901 * boxed object in the arg array with the copy.
4903 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4904 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4905 return_val_if_nok (error, NULL);
4906 mono_array_setref (params, i, copy);
4909 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4910 if (!t->byref && was_null)
4911 mono_array_setref (params, i, NULL);
4914 case MONO_TYPE_STRING:
4915 case MONO_TYPE_OBJECT:
4916 case MONO_TYPE_CLASS:
4917 case MONO_TYPE_ARRAY:
4918 case MONO_TYPE_SZARRAY:
4920 result = mono_array_addr (params, MonoObject*, i);
4921 // FIXME: I need to check this code path
4923 result = mono_array_get (params, MonoObject*, i);
4925 case MONO_TYPE_GENERICINST:
4927 t = &t->data.generic_class->container_class->this_arg;
4929 t = &t->data.generic_class->container_class->byval_arg;
4931 case MONO_TYPE_PTR: {
4934 /* The argument should be an IntPtr */
4935 arg = mono_array_get (params, MonoObject*, i);
4939 g_assert (arg->vtable->klass == mono_defaults.int_class);
4940 result = ((MonoIntPtr*)arg)->m_value;
4945 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4950 * mono_runtime_invoke_array:
4951 * \param method method to invoke
4952 * \param obj object instance
4953 * \param params arguments to the method
4954 * \param exc exception information.
4955 * Invokes the method represented by \p method on the object \p obj.
4957 * \p obj is the \c this pointer, it should be NULL for static
4958 * methods, a \c MonoObject* for object instances and a pointer to
4959 * the value type for value types.
4961 * The \p params array contains the arguments to the method with the
4962 * same convention: \c MonoObject* pointers for object instances and
4963 * pointers to the value type otherwise. The \c _invoke_array
4964 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
4965 * in this case the value types are boxed inside the
4966 * respective reference representation.
4968 * From unmanaged code you'll usually use the
4969 * mono_runtime_invoke_checked() variant.
4971 * Note that this function doesn't handle virtual methods for
4972 * you, it will exec the exact method you pass: we still need to
4973 * expose a function to lookup the derived class implementation
4974 * of a virtual method (there are examples of this in the code,
4977 * You can pass NULL as the \p exc argument if you don't want to
4978 * catch exceptions, otherwise, \c *exc will be set to the exception
4979 * thrown, if any. if an exception is thrown, you can't use the
4980 * \c MonoObject* result from the function.
4982 * If the method returns a value type, it is boxed in an object
4986 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4991 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4993 mono_error_cleanup (&error);
4996 if (!is_ok (&error))
4997 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
5001 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5002 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5008 * mono_runtime_invoke_array_checked:
5009 * \param method method to invoke
5010 * \param obj object instance
5011 * \param params arguments to the method
5012 * \param error set on failure.
5013 * Invokes the method represented by \p method on the object \p obj.
5015 * \p obj is the \c this pointer, it should be NULL for static
5016 * methods, a \c MonoObject* for object instances and a pointer to
5017 * the value type for value types.
5019 * The \p params array contains the arguments to the method with the
5020 * same convention: \c MonoObject* pointers for object instances and
5021 * pointers to the value type otherwise. The \c _invoke_array
5022 * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5023 * in this case the value types are boxed inside the
5024 * respective reference representation.
5026 * From unmanaged code you'll usually use the
5027 * mono_runtime_invoke_checked() variant.
5029 * Note that this function doesn't handle virtual methods for
5030 * you, it will exec the exact method you pass: we still need to
5031 * expose a function to lookup the derived class implementation
5032 * of a virtual method (there are examples of this in the code,
5035 * On failure or exception, \p error will be set. In that case, you
5036 * can't use the \c MonoObject* result from the function.
5038 * If the method returns a value type, it is boxed in an object
5042 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5046 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5050 * mono_runtime_try_invoke_array:
5051 * \param method method to invoke
5052 * \param obj object instance
5053 * \param params arguments to the method
5054 * \param exc exception information.
5055 * \param error set on failure.
5056 * Invokes the method represented by \p method on the object \p obj.
5058 * \p obj is the \c this pointer, it should be NULL for static
5059 * methods, a \c MonoObject* for object instances and a pointer to
5060 * the value type for value types.
5062 * The \p params array contains the arguments to the method with the
5063 * same convention: \c MonoObject* pointers for object instances and
5064 * pointers to the value type otherwise. The \c _invoke_array
5065 * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5066 * in this case the value types are boxed inside the
5067 * respective reference representation.
5069 * From unmanaged code you'll usually use the
5070 * mono_runtime_invoke_checked() variant.
5072 * Note that this function doesn't handle virtual methods for
5073 * you, it will exec the exact method you pass: we still need to
5074 * expose a function to lookup the derived class implementation
5075 * of a virtual method (there are examples of this in the code,
5078 * You can pass NULL as the \p exc argument if you don't want to catch
5079 * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5080 * any. On other failures, \p error will be set. If an exception is
5081 * thrown or there's an error, you can't use the \c MonoObject* result
5082 * from the function.
5084 * If the method returns a value type, it is boxed in an object
5088 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5089 MonoObject **exc, MonoError *error)
5091 MONO_REQ_GC_UNSAFE_MODE;
5095 MonoMethodSignature *sig = mono_method_signature (method);
5096 gpointer *pa = NULL;
5099 gboolean has_byref_nullables = FALSE;
5101 if (NULL != params) {
5102 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5103 for (i = 0; i < mono_array_length (params); i++) {
5104 MonoType *t = sig->params [i];
5105 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5106 return_val_if_nok (error, NULL);
5110 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5113 if (mono_class_is_nullable (method->klass)) {
5114 /* Need to create a boxed vtype instead */
5120 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5125 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5126 mono_error_assert_ok (error);
5127 g_assert (obj); /*maybe we should raise a TLE instead?*/
5128 #ifndef DISABLE_REMOTING
5129 if (mono_object_is_transparent_proxy (obj)) {
5130 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5133 if (method->klass->valuetype)
5134 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5137 } else if (method->klass->valuetype) {
5138 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5139 return_val_if_nok (error, NULL);
5143 mono_runtime_try_invoke (method, o, pa, exc, error);
5145 mono_runtime_invoke_checked (method, o, pa, error);
5148 return (MonoObject *)obj;
5150 if (mono_class_is_nullable (method->klass)) {
5151 MonoObject *nullable;
5153 /* Convert the unboxed vtype into a Nullable structure */
5154 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5155 return_val_if_nok (error, NULL);
5157 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5158 return_val_if_nok (error, NULL);
5159 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5160 obj = mono_object_unbox (nullable);
5163 /* obj must be already unboxed if needed */
5165 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5167 res = mono_runtime_invoke_checked (method, obj, pa, error);
5169 return_val_if_nok (error, NULL);
5171 if (sig->ret->type == MONO_TYPE_PTR) {
5172 MonoClass *pointer_class;
5173 static MonoMethod *box_method;
5175 MonoObject *box_exc;
5178 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5179 * convert it to a Pointer object.
5181 pointer_class = mono_class_get_pointer_class ();
5183 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5185 g_assert (res->vtable->klass == mono_defaults.int_class);
5186 box_args [0] = ((MonoIntPtr*)res)->m_value;
5187 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5188 return_val_if_nok (error, NULL);
5190 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5191 g_assert (box_exc == NULL);
5192 mono_error_assert_ok (error);
5195 if (has_byref_nullables) {
5197 * The runtime invoke wrapper already converted byref nullables back,
5198 * and stored them in pa, we just need to copy them back to the
5201 for (i = 0; i < mono_array_length (params); i++) {
5202 MonoType *t = sig->params [i];
5204 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5205 mono_array_setref (params, i, pa [i]);
5215 * \param klass the class of the object that we want to create
5216 * \returns a newly created object whose definition is
5217 * looked up using \p klass. This will not invoke any constructors,
5218 * so the consumer of this routine has to invoke any constructors on
5219 * its own to initialize the object.
5221 * It returns NULL on failure.
5224 mono_object_new (MonoDomain *domain, MonoClass *klass)
5226 MONO_REQ_GC_UNSAFE_MODE;
5230 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5232 mono_error_cleanup (&error);
5237 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5239 MONO_REQ_GC_UNSAFE_MODE;
5243 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5245 mono_error_set_pending_exception (&error);
5250 * mono_object_new_checked:
5251 * \param klass the class of the object that we want to create
5252 * \param error set on error
5253 * \returns a newly created object whose definition is
5254 * looked up using \p klass. This will not invoke any constructors,
5255 * so the consumer of this routine has to invoke any constructors on
5256 * its own to initialize the object.
5258 * It returns NULL on failure and sets \p error.
5261 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5263 MONO_REQ_GC_UNSAFE_MODE;
5267 vtable = mono_class_vtable_full (domain, klass, error);
5271 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5276 * mono_object_new_pinned:
5278 * Same as mono_object_new, but the returned object will be pinned.
5279 * For SGEN, these objects will only be freed at appdomain unload.
5282 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5284 MONO_REQ_GC_UNSAFE_MODE;
5290 vtable = mono_class_vtable (domain, klass);
5291 g_assert (vtable); /* FIXME don't swallow the error */
5293 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5295 if (G_UNLIKELY (!o))
5296 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5297 else if (G_UNLIKELY (vtable->klass->has_finalize))
5298 mono_object_register_finalizer (o);
5304 * mono_object_new_specific:
5305 * \param vtable the vtable of the object that we want to create
5306 * \returns A newly created object with class and domain specified
5310 mono_object_new_specific (MonoVTable *vtable)
5313 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5314 mono_error_cleanup (&error);
5320 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5322 MONO_REQ_GC_UNSAFE_MODE;
5328 /* check for is_com_object for COM Interop */
5329 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5332 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5335 MonoClass *klass = mono_class_get_activation_services_class ();
5338 mono_class_init (klass);
5340 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5342 mono_error_set_not_supported (error, "Linked away.");
5345 vtable->domain->create_proxy_for_type_method = im;
5348 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5349 if (!mono_error_ok (error))
5352 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5353 if (!mono_error_ok (error))
5360 return mono_object_new_alloc_specific_checked (vtable, error);
5364 ves_icall_object_new_specific (MonoVTable *vtable)
5367 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5368 mono_error_set_pending_exception (&error);
5374 * mono_object_new_alloc_specific:
5375 * \param vtable virtual table for the object.
5376 * This function allocates a new \c MonoObject with the type derived
5377 * from the \p vtable information. If the class of this object has a
5378 * finalizer, then the object will be tracked for finalization.
5380 * This method might raise an exception on errors. Use the
5381 * \c mono_object_new_fast_checked method if you want to manually raise
5384 * \returns the allocated object.
5387 mono_object_new_alloc_specific (MonoVTable *vtable)
5390 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5391 mono_error_cleanup (&error);
5397 * mono_object_new_alloc_specific_checked:
5398 * \param vtable virtual table for the object.
5399 * \param error holds the error return value.
5401 * This function allocates a new \c MonoObject with the type derived
5402 * from the \p vtable information. If the class of this object has a
5403 * finalizer, then the object will be tracked for finalization.
5405 * If there is not enough memory, the \p error parameter will be set
5406 * and will contain a user-visible message with the amount of bytes
5407 * that were requested.
5409 * \returns the allocated object, or NULL if there is not enough memory
5412 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5414 MONO_REQ_GC_UNSAFE_MODE;
5420 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5422 if (G_UNLIKELY (!o))
5423 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5424 else if (G_UNLIKELY (vtable->klass->has_finalize))
5425 mono_object_register_finalizer (o);
5431 * mono_object_new_fast:
5432 * \param vtable virtual table for the object.
5434 * This function allocates a new \c MonoObject with the type derived
5435 * from the \p vtable information. The returned object is not tracked
5436 * for finalization. If your object implements a finalizer, you should
5437 * use \c mono_object_new_alloc_specific instead.
5439 * This method might raise an exception on errors. Use the
5440 * \c mono_object_new_fast_checked method if you want to manually raise
5443 * \returns the allocated object.
5446 mono_object_new_fast (MonoVTable *vtable)
5449 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5450 mono_error_cleanup (&error);
5456 * mono_object_new_fast_checked:
5457 * \param vtable virtual table for the object.
5458 * \param error holds the error return value.
5460 * This function allocates a new \c MonoObject with the type derived
5461 * from the \p vtable information. The returned object is not tracked
5462 * for finalization. If your object implements a finalizer, you should
5463 * use \c mono_object_new_alloc_specific_checked instead.
5465 * If there is not enough memory, the \p error parameter will be set
5466 * and will contain a user-visible message with the amount of bytes
5467 * that were requested.
5469 * \returns the allocated object, or NULL if there is not enough memory
5472 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5474 MONO_REQ_GC_UNSAFE_MODE;
5480 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5482 if (G_UNLIKELY (!o))
5483 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5489 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5491 MONO_REQ_GC_UNSAFE_MODE;
5497 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5499 if (G_UNLIKELY (!o))
5500 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5501 else if (G_UNLIKELY (vtable->klass->has_finalize))
5502 mono_object_register_finalizer (o);
5508 * mono_object_new_from_token:
5509 * \param image Context where the type_token is hosted
5510 * \param token a token of the type that we want to create
5511 * \returns A newly created object whose definition is
5512 * looked up using \p token in the \p image image
5515 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5517 MONO_REQ_GC_UNSAFE_MODE;
5523 klass = mono_class_get_checked (image, token, &error);
5524 mono_error_assert_ok (&error);
5526 result = mono_object_new_checked (domain, klass, &error);
5528 mono_error_cleanup (&error);
5535 * mono_object_clone:
5536 * \param obj the object to clone
5537 * \returns A newly created object who is a shallow copy of \p obj
5540 mono_object_clone (MonoObject *obj)
5543 MonoObject *o = mono_object_clone_checked (obj, &error);
5544 mono_error_cleanup (&error);
5550 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5552 MONO_REQ_GC_UNSAFE_MODE;
5559 size = obj->vtable->klass->instance_size;
5561 if (obj->vtable->klass->rank)
5562 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5564 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5566 if (G_UNLIKELY (!o)) {
5567 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5571 /* If the object doesn't contain references this will do a simple memmove. */
5572 mono_gc_wbarrier_object_copy (o, obj);
5574 if (obj->vtable->klass->has_finalize)
5575 mono_object_register_finalizer (o);
5580 * mono_array_full_copy:
5581 * \param src source array to copy
5582 * \param dest destination array
5583 * Copies the content of one array to another with exactly the same type and size.
5586 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5588 MONO_REQ_GC_UNSAFE_MODE;
5591 MonoClass *klass = src->obj.vtable->klass;
5593 g_assert (klass == dest->obj.vtable->klass);
5595 size = mono_array_length (src);
5596 g_assert (size == mono_array_length (dest));
5597 size *= mono_array_element_size (klass);
5599 array_full_copy_unchecked_size (src, dest, klass, size);
5603 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5605 if (mono_gc_is_moving ()) {
5606 if (klass->element_class->valuetype) {
5607 if (klass->element_class->has_references)
5608 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5610 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5612 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5615 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5620 * mono_array_clone_in_domain:
5621 * \param domain the domain in which the array will be cloned into
5622 * \param array the array to clone
5623 * \param error set on error
5624 * This routine returns a copy of the array that is hosted on the
5625 * specified \c MonoDomain. On failure returns NULL and sets \p error.
5628 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5630 MONO_REQ_GC_UNSAFE_MODE;
5632 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5634 MonoClass *klass = mono_handle_class (array_handle);
5638 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5639 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5641 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5643 if (array_bounds == NULL) {
5644 size = mono_array_handle_length (array_handle);
5645 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5648 size *= mono_array_element_size (klass);
5650 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5651 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5652 size = mono_array_element_size (klass);
5653 for (int i = 0; i < klass->rank; ++i) {
5654 sizes [i] = array_bounds [i].length;
5655 size *= array_bounds [i].length;
5656 lower_bounds [i] = array_bounds [i].lower_bound;
5658 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5663 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5664 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5665 mono_gchandle_free (dst_handle);
5667 MONO_HANDLE_ASSIGN (result, o);
5670 mono_gchandle_free (src_handle);
5676 * \param array the array to clone
5677 * \returns A newly created array who is a shallow copy of \p array
5680 mono_array_clone (MonoArray *array)
5682 MONO_REQ_GC_UNSAFE_MODE;
5685 MonoArray *result = mono_array_clone_checked (array, &error);
5686 mono_error_cleanup (&error);
5691 * mono_array_clone_checked:
5692 * \param array the array to clone
5693 * \param error set on error
5694 * \returns A newly created array who is a shallow copy of \p array. On
5695 * failure returns NULL and sets \p error.
5698 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5700 MONO_REQ_GC_UNSAFE_MODE;
5701 HANDLE_FUNCTION_ENTER ();
5702 /* FIXME: callers of mono_array_clone_checked should use handles */
5704 MONO_HANDLE_DCL (MonoArray, array);
5705 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5706 HANDLE_FUNCTION_RETURN_OBJ (result);
5709 /* helper macros to check for overflow when calculating the size of arrays */
5710 #ifdef MONO_BIG_ARRAYS
5711 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5712 #define MYGUINT_MAX MYGUINT64_MAX
5713 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5714 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5715 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5716 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5717 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5719 #define MYGUINT32_MAX 4294967295U
5720 #define MYGUINT_MAX MYGUINT32_MAX
5721 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5722 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5723 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5724 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5725 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5729 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5731 MONO_REQ_GC_NEUTRAL_MODE;
5735 byte_len = mono_array_element_size (klass);
5736 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5739 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5741 byte_len += MONO_SIZEOF_MONO_ARRAY;
5749 * mono_array_new_full:
5750 * \param domain domain where the object is created
5751 * \param array_class array class
5752 * \param lengths lengths for each dimension in the array
5753 * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5754 * This routine creates a new array object with the given dimensions,
5755 * lower bounds and type.
5758 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5761 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5762 mono_error_cleanup (&error);
5768 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5770 MONO_REQ_GC_UNSAFE_MODE;
5772 uintptr_t byte_len = 0, len, bounds_size;
5775 MonoArrayBounds *bounds;
5781 if (!array_class->inited)
5782 mono_class_init (array_class);
5786 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5787 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5789 if (len > MONO_ARRAY_MAX_INDEX) {
5790 mono_error_set_generic_error (error, "System", "OverflowException", "");
5795 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5797 for (i = 0; i < array_class->rank; ++i) {
5798 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5799 mono_error_set_generic_error (error, "System", "OverflowException", "");
5802 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5803 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5810 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5811 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5817 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5818 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5821 byte_len = (byte_len + 3) & ~3;
5822 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5823 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5826 byte_len += bounds_size;
5829 * Following three lines almost taken from mono_object_new ():
5830 * they need to be kept in sync.
5832 vtable = mono_class_vtable_full (domain, array_class, error);
5833 return_val_if_nok (error, NULL);
5836 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5838 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5840 if (G_UNLIKELY (!o)) {
5841 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5845 array = (MonoArray*)o;
5847 bounds = array->bounds;
5850 for (i = 0; i < array_class->rank; ++i) {
5851 bounds [i].length = lengths [i];
5853 bounds [i].lower_bound = lower_bounds [i];
5862 * \param domain domain where the object is created
5863 * \param eclass element class
5864 * \param n number of array elements
5865 * This routine creates a new szarray with \p n elements of type \p eclass.
5868 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5870 MONO_REQ_GC_UNSAFE_MODE;
5873 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5874 mono_error_cleanup (&error);
5879 * mono_array_new_checked:
5880 * \param domain domain where the object is created
5881 * \param eclass element class
5882 * \param n number of array elements
5883 * \param error set on error
5884 * This routine creates a new szarray with \p n elements of type \p eclass.
5885 * On failure returns NULL and sets \p error.
5888 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5894 ac = mono_array_class_get (eclass, 1);
5897 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5898 return_val_if_nok (error, NULL);
5900 return mono_array_new_specific_checked (vtable, n, error);
5904 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5907 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5908 mono_error_set_pending_exception (&error);
5914 * mono_array_new_specific:
5915 * \param vtable a vtable in the appropriate domain for an initialized class
5916 * \param n number of array elements
5917 * This routine is a fast alternative to \c mono_array_new for code which
5918 * can be sure about the domain it operates in.
5921 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5924 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5925 mono_error_cleanup (&error);
5931 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5933 MONO_REQ_GC_UNSAFE_MODE;
5940 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5941 mono_error_set_generic_error (error, "System", "OverflowException", "");
5945 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5946 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5949 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5951 if (G_UNLIKELY (!o)) {
5952 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5956 return (MonoArray*)o;
5960 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5963 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5964 mono_error_set_pending_exception (&error);
5970 * mono_string_empty_wrapper:
5972 * Returns: The same empty string instance as the managed string.Empty
5975 mono_string_empty_wrapper (void)
5977 MonoDomain *domain = mono_domain_get ();
5978 return mono_string_empty (domain);
5982 * mono_string_empty:
5984 * Returns: The same empty string instance as the managed string.Empty
5987 mono_string_empty (MonoDomain *domain)
5990 g_assert (domain->empty_string);
5991 return domain->empty_string;
5995 * mono_string_new_utf16:
5996 * \param text a pointer to an utf16 string
5997 * \param len the length of the string
5998 * \returns A newly created string object which contains \p text.
6001 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6003 MONO_REQ_GC_UNSAFE_MODE;
6006 MonoString *res = NULL;
6007 res = mono_string_new_utf16_checked (domain, text, len, &error);
6008 mono_error_cleanup (&error);
6014 * mono_string_new_utf16_checked:
6015 * \param text a pointer to an utf16 string
6016 * \param len the length of the string
6017 * \param error written on error.
6018 * \returns A newly created string object which contains \p text.
6019 * On error, returns NULL and sets \p error.
6022 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6024 MONO_REQ_GC_UNSAFE_MODE;
6030 s = mono_string_new_size_checked (domain, len, error);
6032 memcpy (mono_string_chars (s), text, len * 2);
6038 * mono_string_new_utf16_handle:
6039 * \param text a pointer to an utf16 string
6040 * \param len the length of the string
6041 * \param error written on error.
6042 * \returns A newly created string object which contains \p text.
6043 * On error, returns NULL and sets \p error.
6046 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6048 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6052 * mono_string_new_utf32_checked:
6053 * \param text a pointer to an utf32 string
6054 * \param len the length of the string
6055 * \param error set on failure.
6056 * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6059 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6061 MONO_REQ_GC_UNSAFE_MODE;
6064 mono_unichar2 *utf16_output = NULL;
6065 gint32 utf16_len = 0;
6066 GError *gerror = NULL;
6067 glong items_written;
6070 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6073 g_error_free (gerror);
6075 while (utf16_output [utf16_len]) utf16_len++;
6077 s = mono_string_new_size_checked (domain, utf16_len, error);
6078 return_val_if_nok (error, NULL);
6080 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6082 g_free (utf16_output);
6088 * mono_string_new_utf32:
6089 * \param text a pointer to a UTF-32 string
6090 * \param len the length of the string
6091 * \returns A newly created string object which contains \p text.
6094 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6097 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6098 mono_error_cleanup (&error);
6103 * mono_string_new_size:
6104 * \param text a pointer to a UTF-16 string
6105 * \param len the length of the string
6106 * \returns A newly created string object of \p len
6109 mono_string_new_size (MonoDomain *domain, gint32 len)
6112 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6113 mono_error_cleanup (&error);
6119 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6121 MONO_REQ_GC_UNSAFE_MODE;
6129 /* check for overflow */
6130 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6131 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6135 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6136 g_assert (size > 0);
6138 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6141 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6143 if (G_UNLIKELY (!s)) {
6144 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6152 * mono_string_new_len:
6153 * \param text a pointer to an utf8 string
6154 * \param length number of bytes in \p text to consider
6155 * \returns A newly created string object which contains \p text.
6158 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6160 MONO_REQ_GC_UNSAFE_MODE;
6163 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6164 mono_error_cleanup (&error);
6169 * mono_string_new_len_checked:
6170 * \param text a pointer to an utf8 string
6171 * \param length number of bytes in \p text to consider
6172 * \param error set on error
6173 * \returns A newly created string object which contains \p text. On
6174 * failure returns NULL and sets \p error.
6177 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6179 MONO_REQ_GC_UNSAFE_MODE;
6183 GError *eg_error = NULL;
6184 MonoString *o = NULL;
6186 glong items_written;
6188 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6191 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6193 g_error_free (eg_error);
6202 * \param text a pointer to a UTF-8 string
6203 * \deprecated Use \c mono_string_new_checked in new code.
6204 * This function asserts if it cannot allocate a new string.
6205 * \returns A newly created string object which contains \p text.
6208 mono_string_new (MonoDomain *domain, const char *text)
6211 MonoString *res = NULL;
6212 res = mono_string_new_checked (domain, text, &error);
6213 mono_error_assert_ok (&error);
6218 * mono_string_new_checked:
6219 * \param text a pointer to an utf8 string
6220 * \param merror set on error
6221 * \returns A newly created string object which contains \p text.
6222 * On error returns NULL and sets \p merror.
6225 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6227 MONO_REQ_GC_UNSAFE_MODE;
6229 GError *eg_error = NULL;
6230 MonoString *o = NULL;
6232 glong items_written;
6239 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6242 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6244 mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6249 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6254 MonoString *o = NULL;
6256 if (!g_utf8_validate (text, -1, &end)) {
6257 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6261 len = g_utf8_strlen (text, -1);
6262 o = mono_string_new_size_checked (domain, len, error);
6265 str = mono_string_chars (o);
6267 while (text < end) {
6268 *str++ = g_utf8_get_char (text);
6269 text = g_utf8_next_char (text);
6278 * mono_string_new_wrapper:
6279 * \param text pointer to UTF-8 characters.
6280 * Helper function to create a string object from \p text in the current domain.
6283 mono_string_new_wrapper (const char *text)
6285 MONO_REQ_GC_UNSAFE_MODE;
6287 MonoDomain *domain = mono_domain_get ();
6291 MonoString *result = mono_string_new_checked (domain, text, &error);
6292 mono_error_assert_ok (&error);
6301 * \param class the class of the value
6302 * \param value a pointer to the unboxed data
6303 * \returns A newly created object which contains \p value.
6306 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6309 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6310 mono_error_cleanup (&error);
6315 * mono_value_box_checked:
6316 * \param domain the domain of the new object
6317 * \param class the class of the value
6318 * \param value a pointer to the unboxed data
6319 * \param error set on error
6320 * \returns A newly created object which contains \p value. On failure
6321 * returns NULL and sets \p error.
6324 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6326 MONO_REQ_GC_UNSAFE_MODE;
6333 g_assert (klass->valuetype);
6334 if (mono_class_is_nullable (klass))
6335 return mono_nullable_box ((guint8 *)value, klass, error);
6337 vtable = mono_class_vtable (domain, klass);
6340 size = mono_class_instance_size (klass);
6341 res = mono_object_new_alloc_specific_checked (vtable, error);
6342 return_val_if_nok (error, NULL);
6344 size = size - sizeof (MonoObject);
6346 if (mono_gc_is_moving ()) {
6347 g_assert (size == mono_class_value_size (klass, NULL));
6348 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6350 #if NO_UNALIGNED_ACCESS
6351 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6355 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6358 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6361 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6364 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6367 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6371 if (klass->has_finalize) {
6372 mono_object_register_finalizer (res);
6373 return_val_if_nok (error, NULL);
6380 * \param dest destination pointer
6381 * \param src source pointer
6382 * \param klass a valuetype class
6383 * Copy a valuetype from \p src to \p dest. This function must be used
6384 * when \p klass contains reference fields.
6387 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6389 MONO_REQ_GC_UNSAFE_MODE;
6391 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6395 * mono_value_copy_array:
6396 * \param dest destination array
6397 * \param dest_idx index in the \p dest array
6398 * \param src source pointer
6399 * \param count number of items
6400 * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6401 * This function must be used when \p klass contains references fields.
6402 * Overlap is handled.
6405 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6407 MONO_REQ_GC_UNSAFE_MODE;
6409 int size = mono_array_element_size (dest->obj.vtable->klass);
6410 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6411 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6412 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6416 * mono_object_get_domain:
6417 * \param obj object to query
6418 * \returns the \c MonoDomain where the object is hosted
6421 mono_object_get_domain (MonoObject *obj)
6423 MONO_REQ_GC_UNSAFE_MODE;
6425 return mono_object_domain (obj);
6429 * mono_object_get_class:
6430 * \param obj object to query
6431 * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6432 * \returns the \c MonoClass of the object.
6435 mono_object_get_class (MonoObject *obj)
6437 MONO_REQ_GC_UNSAFE_MODE;
6439 return mono_object_class (obj);
6442 * mono_object_get_size:
6443 * \param o object to query
6444 * \returns the size, in bytes, of \p o
6447 mono_object_get_size (MonoObject* o)
6449 MONO_REQ_GC_UNSAFE_MODE;
6451 MonoClass* klass = mono_object_class (o);
6452 if (klass == mono_defaults.string_class) {
6453 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6454 } else if (o->vtable->rank) {
6455 MonoArray *array = (MonoArray*)o;
6456 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6457 if (array->bounds) {
6460 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6464 return mono_class_instance_size (klass);
6469 * mono_object_unbox:
6470 * \param obj object to unbox
6471 * \returns a pointer to the start of the valuetype boxed in this
6474 * This method will assert if the object passed is not a valuetype.
6477 mono_object_unbox (MonoObject *obj)
6479 MONO_REQ_GC_UNSAFE_MODE;
6481 /* add assert for valuetypes? */
6482 g_assert (obj->vtable->klass->valuetype);
6483 return ((char*)obj) + sizeof (MonoObject);
6487 * mono_object_isinst:
6488 * \param obj an object
6489 * \param klass a pointer to a class
6490 * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6493 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6495 MONO_REQ_GC_UNSAFE_MODE;
6497 HANDLE_FUNCTION_ENTER ();
6498 MONO_HANDLE_DCL (MonoObject, obj);
6500 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6501 mono_error_cleanup (&error);
6502 HANDLE_FUNCTION_RETURN_OBJ (result);
6507 * mono_object_isinst_checked:
6508 * \param obj an object
6509 * \param klass a pointer to a class
6510 * \param error set on error
6511 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6512 * On failure returns NULL and sets \p error.
6515 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6517 MONO_REQ_GC_UNSAFE_MODE;
6519 HANDLE_FUNCTION_ENTER ();
6521 MONO_HANDLE_DCL (MonoObject, obj);
6522 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6523 HANDLE_FUNCTION_RETURN_OBJ (result);
6527 * mono_object_handle_isinst:
6528 * \param obj an object
6529 * \param klass a pointer to a class
6530 * \param error set on error
6531 * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6532 * On failure returns NULL and sets \p error.
6535 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6540 mono_class_init (klass);
6542 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6543 return mono_object_handle_isinst_mbyref (obj, klass, error);
6546 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6548 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6549 MONO_HANDLE_ASSIGN (result, obj);
6554 * mono_object_isinst_mbyref:
6557 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6559 MONO_REQ_GC_UNSAFE_MODE;
6561 HANDLE_FUNCTION_ENTER ();
6563 MONO_HANDLE_DCL (MonoObject, obj);
6564 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6565 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6566 HANDLE_FUNCTION_RETURN_OBJ (result);
6570 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6574 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6576 if (MONO_HANDLE_IS_NULL (obj))
6579 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6581 if (mono_class_is_interface (klass)) {
6582 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6583 MONO_HANDLE_ASSIGN (result, obj);
6587 /* casting an array one of the invariant interfaces that must act as such */
6588 if (klass->is_array_special_interface) {
6589 if (mono_class_is_assignable_from (klass, vt->klass)) {
6590 MONO_HANDLE_ASSIGN (result, obj);
6595 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6596 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6597 MONO_HANDLE_ASSIGN (result, obj);
6601 MonoClass *oklass = vt->klass;
6602 if (mono_class_is_transparent_proxy (oklass)){
6603 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6604 oklass = remote_class->proxy_class;
6607 mono_class_setup_supertypes (klass);
6608 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6609 MONO_HANDLE_ASSIGN (result, obj);
6613 #ifndef DISABLE_REMOTING
6614 if (mono_class_is_transparent_proxy (vt->klass))
6616 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6617 if (!custom_type_info)
6619 MonoDomain *domain = mono_domain_get ();
6620 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6621 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6622 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6623 MonoMethod *im = NULL;
6626 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6628 mono_error_set_not_supported (error, "Linked away.");
6631 im = mono_object_handle_get_virtual_method (rp, im, error);
6636 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6640 pa [0] = MONO_HANDLE_RAW (reftype);
6641 pa [1] = MONO_HANDLE_RAW (obj);
6642 MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6646 if (*(MonoBoolean *) mono_object_unbox(res)) {
6647 /* Update the vtable of the remote type, so it can safely cast to this new type */
6648 mono_upgrade_remote_class (domain, obj, klass, error);
6651 MONO_HANDLE_ASSIGN (result, obj);
6654 #endif /* DISABLE_REMOTING */
6660 * mono_object_castclass_mbyref:
6661 * \param obj an object
6662 * \param klass a pointer to a class
6663 * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6666 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6668 MONO_REQ_GC_UNSAFE_MODE;
6669 HANDLE_FUNCTION_ENTER ();
6671 MONO_HANDLE_DCL (MonoObject, obj);
6672 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6673 if (MONO_HANDLE_IS_NULL (obj))
6675 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6676 mono_error_cleanup (&error);
6678 HANDLE_FUNCTION_RETURN_OBJ (result);
6682 MonoDomain *orig_domain;
6688 str_lookup (MonoDomain *domain, gpointer user_data)
6690 MONO_REQ_GC_UNSAFE_MODE;
6692 LDStrInfo *info = (LDStrInfo *)user_data;
6693 if (info->res || domain == info->orig_domain)
6695 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6699 mono_string_get_pinned (MonoString *str, MonoError *error)
6701 MONO_REQ_GC_UNSAFE_MODE;
6705 /* We only need to make a pinned version of a string if this is a moving GC */
6706 if (!mono_gc_is_moving ())
6710 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6711 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6713 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6714 news->length = mono_string_length (str);
6716 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6722 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6724 MONO_REQ_GC_UNSAFE_MODE;
6726 MonoGHashTable *ldstr_table;
6727 MonoString *s, *res;
6732 domain = ((MonoObject *)str)->vtable->domain;
6733 ldstr_table = domain->ldstr_table;
6735 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6741 /* Allocate outside the lock */
6743 s = mono_string_get_pinned (str, error);
6744 return_val_if_nok (error, NULL);
6747 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6752 mono_g_hash_table_insert (ldstr_table, s, s);
6757 LDStrInfo ldstr_info;
6758 ldstr_info.orig_domain = domain;
6759 ldstr_info.ins = str;
6760 ldstr_info.res = NULL;
6762 mono_domain_foreach (str_lookup, &ldstr_info);
6763 if (ldstr_info.res) {
6765 * the string was already interned in some other domain:
6766 * intern it in the current one as well.
6768 mono_g_hash_table_insert (ldstr_table, str, str);
6778 * mono_string_is_interned:
6779 * \param o String to probe
6780 * \returns Whether the string has been interned.
6783 mono_string_is_interned (MonoString *o)
6786 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6787 /* This function does not fail. */
6788 mono_error_assert_ok (&error);
6793 * mono_string_intern:
6794 * \param o String to intern
6795 * Interns the string passed.
6796 * \returns The interned string.
6799 mono_string_intern (MonoString *str)
6802 MonoString *result = mono_string_intern_checked (str, &error);
6803 mono_error_assert_ok (&error);
6808 * mono_string_intern_checked:
6809 * \param o String to intern
6810 * \param error set on error.
6811 * Interns the string passed.
6812 * \returns The interned string. On failure returns NULL and sets \p error
6815 mono_string_intern_checked (MonoString *str, MonoError *error)
6817 MONO_REQ_GC_UNSAFE_MODE;
6821 return mono_string_is_interned_lookup (str, TRUE, error);
6826 * \param domain the domain where the string will be used.
6827 * \param image a metadata context
6828 * \param idx index into the user string table.
6829 * Implementation for the \c ldstr opcode.
6830 * \returns a loaded string from the \p image / \p idx combination.
6833 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6836 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6837 mono_error_cleanup (&error);
6842 * mono_ldstr_checked:
6843 * \param domain the domain where the string will be used.
6844 * \param image a metadata context
6845 * \param idx index into the user string table.
6846 * \param error set on error.
6847 * Implementation for the \c ldstr opcode.
6848 * \returns A loaded string from the \p image / \p idx combination.
6849 * On failure returns NULL and sets \p error.
6852 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6854 MONO_REQ_GC_UNSAFE_MODE;
6857 if (image->dynamic) {
6858 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6861 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6862 return NULL; /*FIXME we should probably be raising an exception here*/
6863 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6869 * mono_ldstr_metadata_sig
6870 * \param domain the domain for the string
6871 * \param sig the signature of a metadata string
6872 * \param error set on error
6873 * \returns a \c MonoString for a string stored in the metadata. On
6874 * failure returns NULL and sets \p error.
6877 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6879 MONO_REQ_GC_UNSAFE_MODE;
6882 const char *str = sig;
6883 MonoString *o, *interned;
6886 len2 = mono_metadata_decode_blob_size (str, &str);
6889 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6890 return_val_if_nok (error, NULL);
6891 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6894 guint16 *p2 = (guint16*)mono_string_chars (o);
6895 for (i = 0; i < len2; ++i) {
6896 *p2 = GUINT16_FROM_LE (*p2);
6902 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6905 return interned; /* o will get garbage collected */
6907 o = mono_string_get_pinned (o, error);
6910 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6912 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6924 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6928 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6934 GError *gerror = NULL;
6938 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6939 return NULL; /*FIXME we should probably be raising an exception here*/
6940 str = mono_metadata_user_string (image, idx);
6942 len2 = mono_metadata_decode_blob_size (str, &str);
6945 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6947 mono_error_set_argument (error, "string", "%s", gerror->message);
6948 g_error_free (gerror);
6951 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6952 if (len2 > written) {
6953 /* allocate the total length and copy the part of the string that has been converted */
6954 char *as2 = (char *)g_malloc0 (len2);
6955 memcpy (as2, as, written);
6964 * mono_string_to_utf8:
6965 * \param s a \c System.String
6966 * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
6967 * \returns the UTF-8 representation for \p s.
6968 * The resulting buffer needs to be freed with \c mono_free().
6971 mono_string_to_utf8 (MonoString *s)
6973 MONO_REQ_GC_UNSAFE_MODE;
6976 char *result = mono_string_to_utf8_checked (s, &error);
6978 if (!is_ok (&error)) {
6979 mono_error_cleanup (&error);
6986 * mono_string_to_utf8_checked:
6987 * \param s a \c System.String
6988 * \param error a \c MonoError.
6989 * Converts a \c MonoString to its UTF-8 representation. May fail; check
6990 * \p error to determine whether the conversion was successful.
6991 * The resulting buffer should be freed with \c mono_free().
6994 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6996 MONO_REQ_GC_UNSAFE_MODE;
7000 GError *gerror = NULL;
7008 return g_strdup ("");
7010 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7012 mono_error_set_argument (error, "string", "%s", gerror->message);
7013 g_error_free (gerror);
7016 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7017 if (s->length > written) {
7018 /* allocate the total length and copy the part of the string that has been converted */
7019 char *as2 = (char *)g_malloc0 (s->length);
7020 memcpy (as2, as, written);
7029 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7031 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7035 * mono_string_to_utf8_ignore:
7036 * \param s a MonoString
7037 * Converts a \c MonoString to its UTF-8 representation. Will ignore
7038 * invalid surrogate pairs.
7039 * The resulting buffer should be freed with \c mono_free().
7042 mono_string_to_utf8_ignore (MonoString *s)
7044 MONO_REQ_GC_UNSAFE_MODE;
7053 return g_strdup ("");
7055 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7057 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7058 if (s->length > written) {
7059 /* allocate the total length and copy the part of the string that has been converted */
7060 char *as2 = (char *)g_malloc0 (s->length);
7061 memcpy (as2, as, written);
7070 * mono_string_to_utf8_image_ignore:
7071 * \param s a \c System.String
7072 * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7075 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7077 MONO_REQ_GC_UNSAFE_MODE;
7079 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7083 * mono_string_to_utf8_mp_ignore:
7084 * \param s a \c System.String
7085 * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7088 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7090 MONO_REQ_GC_UNSAFE_MODE;
7092 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7097 * mono_string_to_utf16:
7098 * \param s a \c MonoString
7099 * \returns a null-terminated array of the UTF-16 chars
7100 * contained in \p s. The result must be freed with \c g_free().
7101 * This is a temporary helper until our string implementation
7102 * is reworked to always include the null-terminating char.
7105 mono_string_to_utf16 (MonoString *s)
7107 MONO_REQ_GC_UNSAFE_MODE;
7114 as = (char *)g_malloc ((s->length * 2) + 2);
7115 as [(s->length * 2)] = '\0';
7116 as [(s->length * 2) + 1] = '\0';
7119 return (gunichar2 *)(as);
7122 memcpy (as, mono_string_chars(s), s->length * 2);
7123 return (gunichar2 *)(as);
7127 * mono_string_to_utf32:
7128 * \param s a \c MonoString
7129 * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7130 * contained in \p s. The result must be freed with \c g_free().
7133 mono_string_to_utf32 (MonoString *s)
7135 MONO_REQ_GC_UNSAFE_MODE;
7137 mono_unichar4 *utf32_output = NULL;
7138 GError *error = NULL;
7139 glong items_written;
7144 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7147 g_error_free (error);
7149 return utf32_output;
7153 * mono_string_from_utf16:
7154 * \param data the UTF-16 string (LPWSTR) to convert
7155 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7156 * \returns a \c MonoString.
7159 mono_string_from_utf16 (gunichar2 *data)
7162 MonoString *result = mono_string_from_utf16_checked (data, &error);
7163 mono_error_cleanup (&error);
7168 * mono_string_from_utf16_checked:
7169 * \param data the UTF-16 string (LPWSTR) to convert
7170 * \param error set on error
7171 * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7172 * \returns a \c MonoString. On failure sets \p error and returns NULL.
7175 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7178 MONO_REQ_GC_UNSAFE_MODE;
7181 MonoDomain *domain = mono_domain_get ();
7187 while (data [len]) len++;
7189 return mono_string_new_utf16_checked (domain, data, len, error);
7193 * mono_string_from_utf32:
7194 * \param data the UTF-32 string (LPWSTR) to convert
7195 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7196 * \returns a \c MonoString.
7199 mono_string_from_utf32 (mono_unichar4 *data)
7202 MonoString *result = mono_string_from_utf32_checked (data, &error);
7203 mono_error_cleanup (&error);
7208 * mono_string_from_utf32_checked:
7209 * \param data the UTF-32 string (LPWSTR) to convert
7210 * \param error set on error
7211 * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7212 * \returns a \c MonoString. On failure returns NULL and sets \p error.
7215 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7217 MONO_REQ_GC_UNSAFE_MODE;
7220 MonoString* result = NULL;
7221 mono_unichar2 *utf16_output = NULL;
7222 GError *gerror = NULL;
7223 glong items_written;
7229 while (data [len]) len++;
7231 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7234 g_error_free (gerror);
7236 result = mono_string_from_utf16_checked (utf16_output, error);
7237 g_free (utf16_output);
7242 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7244 MONO_REQ_GC_UNSAFE_MODE;
7251 r = mono_string_to_utf8_ignore (s);
7253 r = mono_string_to_utf8_checked (s, error);
7254 if (!mono_error_ok (error))
7261 len = strlen (r) + 1;
7263 mp_s = (char *)mono_mempool_alloc (mp, len);
7265 mp_s = (char *)mono_image_alloc (image, len);
7267 memcpy (mp_s, r, len);
7275 * mono_string_to_utf8_image:
7276 * \param s a \c System.String
7277 * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7280 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7282 MONO_REQ_GC_UNSAFE_MODE;
7284 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7288 * mono_string_to_utf8_mp:
7289 * \param s a \c System.String
7290 * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7293 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7295 MONO_REQ_GC_UNSAFE_MODE;
7297 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7301 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7304 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7306 eh_callbacks = *cbs;
7309 MonoRuntimeExceptionHandlingCallbacks *
7310 mono_get_eh_callbacks (void)
7312 return &eh_callbacks;
7316 * mono_raise_exception:
7317 * \param ex exception object
7318 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7321 mono_raise_exception (MonoException *ex)
7323 MONO_REQ_GC_UNSAFE_MODE;
7326 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7327 * that will cause gcc to omit the function epilog, causing problems when
7328 * the JIT tries to walk the stack, since the return address on the stack
7329 * will point into the next function in the executable, not this one.
7331 eh_callbacks.mono_raise_exception (ex);
7335 * mono_raise_exception:
7336 * \param ex exception object
7337 * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7340 mono_reraise_exception (MonoException *ex)
7342 MONO_REQ_GC_UNSAFE_MODE;
7345 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7346 * that will cause gcc to omit the function epilog, causing problems when
7347 * the JIT tries to walk the stack, since the return address on the stack
7348 * will point into the next function in the executable, not this one.
7350 eh_callbacks.mono_reraise_exception (ex);
7354 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7356 MONO_REQ_GC_UNSAFE_MODE;
7358 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7362 * mono_wait_handle_new:
7363 * \param domain Domain where the object will be created
7364 * \param handle Handle for the wait handle
7365 * \param error set on error.
7366 * \returns A new \c MonoWaitHandle created in the given domain for the
7367 * given handle. On failure returns NULL and sets \p error.
7370 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7372 MONO_REQ_GC_UNSAFE_MODE;
7374 MonoWaitHandle *res;
7375 gpointer params [1];
7376 static MonoMethod *handle_set;
7379 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7380 return_val_if_nok (error, NULL);
7382 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7384 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7386 params [0] = &handle;
7388 mono_runtime_invoke_checked (handle_set, res, params, error);
7393 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7395 MONO_REQ_GC_UNSAFE_MODE;
7397 static MonoClassField *f_safe_handle = NULL;
7400 if (!f_safe_handle) {
7401 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7402 g_assert (f_safe_handle);
7405 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7411 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7413 MONO_REQ_GC_UNSAFE_MODE;
7415 RuntimeInvokeFunction runtime_invoke;
7419 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7420 MonoMethod *method = mono_get_context_capture_method ();
7421 MonoMethod *wrapper;
7424 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7425 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7426 return_val_if_nok (error, NULL);
7427 domain->capture_context_method = mono_compile_method_checked (method, error);
7428 return_val_if_nok (error, NULL);
7431 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7433 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7436 * mono_async_result_new:
7437 * \param domain domain where the object will be created.
7438 * \param handle wait handle.
7439 * \param state state to pass to AsyncResult
7440 * \param data C closure data.
7441 * \param error set on error.
7442 * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7443 * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7444 * On failure returns NULL and sets \p error.
7447 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7449 MONO_REQ_GC_UNSAFE_MODE;
7452 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7453 return_val_if_nok (error, NULL);
7454 MonoObject *context = mono_runtime_capture_context (domain, error);
7455 return_val_if_nok (error, NULL);
7456 /* we must capture the execution context from the original thread */
7458 MONO_OBJECT_SETREF (res, execution_context, context);
7459 /* note: result may be null if the flow is suppressed */
7462 res->data = (void **)data;
7463 MONO_OBJECT_SETREF (res, object_data, object_data);
7464 MONO_OBJECT_SETREF (res, async_state, state);
7465 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7466 return_val_if_nok (error, NULL);
7468 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7470 res->sync_completed = FALSE;
7471 res->completed = FALSE;
7477 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7479 MONO_REQ_GC_UNSAFE_MODE;
7486 g_assert (ares->async_delegate);
7488 ac = (MonoAsyncCall*) ares->object_data;
7490 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7491 if (mono_error_set_pending_exception (&error))
7494 gpointer wait_event = NULL;
7496 ac->msg->exc = NULL;
7498 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7500 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7501 mono_threads_begin_abort_protected_block ();
7503 if (!ac->msg->exc) {
7504 MonoException *ex = mono_error_convert_to_exception (&error);
7505 ac->msg->exc = (MonoObject *)ex;
7507 mono_error_cleanup (&error);
7510 MONO_OBJECT_SETREF (ac, res, res);
7512 mono_monitor_enter ((MonoObject*) ares);
7513 ares->completed = 1;
7515 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7516 mono_monitor_exit ((MonoObject*) ares);
7518 if (wait_event != NULL)
7519 mono_w32event_set (wait_event);
7521 error_init (&error); //the else branch would leave it in an undefined state
7523 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7525 mono_threads_end_abort_protected_block ();
7527 if (mono_error_set_pending_exception (&error))
7535 mono_message_init (MonoDomain *domain,
7536 MonoMethodMessage *this_obj,
7537 MonoReflectionMethod *method,
7538 MonoArray *out_args,
7541 MONO_REQ_GC_UNSAFE_MODE;
7543 static MonoMethod *init_message_method = NULL;
7545 if (!init_message_method) {
7546 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7547 g_assert (init_message_method != NULL);
7551 /* FIXME set domain instead? */
7552 g_assert (domain == mono_domain_get ());
7559 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7560 return is_ok (error);
7563 #ifndef DISABLE_REMOTING
7565 * mono_remoting_invoke:
7566 * \param real_proxy pointer to a \c RealProxy object
7567 * \param msg The \c MonoMethodMessage to execute
7568 * \param exc used to store exceptions
7569 * \param out_args used to store output arguments
7570 * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7571 * \c IMessage interface and it is not trivial to extract results from there. So
7572 * we call an helper method \c PrivateInvoke instead of calling
7573 * \c RealProxy::Invoke() directly.
7574 * \returns the result object.
7577 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7579 MONO_REQ_GC_UNSAFE_MODE;
7582 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7589 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7592 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7594 mono_error_set_not_supported (error, "Linked away.");
7597 real_proxy->vtable->domain->private_invoke_method = im;
7600 pa [0] = real_proxy;
7605 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7606 return_val_if_nok (error, NULL);
7613 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7614 MonoObject **exc, MonoArray **out_args, MonoError *error)
7616 MONO_REQ_GC_UNSAFE_MODE;
7618 static MonoClass *object_array_klass;
7623 MonoMethodSignature *sig;
7625 int i, j, outarg_count = 0;
7627 #ifndef DISABLE_REMOTING
7628 if (target && mono_object_is_transparent_proxy (target)) {
7629 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7630 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7631 target = tp->rp->unwrapped_server;
7633 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7638 domain = mono_domain_get ();
7639 method = msg->method->method;
7640 sig = mono_method_signature (method);
7642 for (i = 0; i < sig->param_count; i++) {
7643 if (sig->params [i]->byref)
7647 if (!object_array_klass) {
7650 klass = mono_array_class_get (mono_defaults.object_class, 1);
7653 mono_memory_barrier ();
7654 object_array_klass = klass;
7657 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7658 return_val_if_nok (error, NULL);
7660 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7663 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7664 return_val_if_nok (error, NULL);
7666 for (i = 0, j = 0; i < sig->param_count; i++) {
7667 if (sig->params [i]->byref) {
7669 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7670 mono_array_setref (*out_args, j, arg);
7679 * prepare_to_string_method:
7681 * @target: Set to @obj or unboxed value if a valuetype
7683 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7686 prepare_to_string_method (MonoObject *obj, void **target)
7688 MONO_REQ_GC_UNSAFE_MODE;
7690 static MonoMethod *to_string = NULL;
7698 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7700 method = mono_object_get_virtual_method (obj, to_string);
7702 // Unbox value type if needed
7703 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7704 *target = mono_object_unbox (obj);
7710 * mono_object_to_string:
7711 * \param obj The object
7712 * \param exc Any exception thrown by \c ToString. May be NULL.
7713 * \returns the result of calling \c ToString on an object.
7716 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7719 MonoString *s = NULL;
7721 MonoMethod *method = prepare_to_string_method (obj, &target);
7723 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7724 if (*exc == NULL && !mono_error_ok (&error))
7725 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7727 mono_error_cleanup (&error);
7729 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7730 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7737 * mono_object_to_string_checked:
7738 * \param obj The object
7739 * \param error Set on error.
7740 * \returns the result of calling \c ToString() on an object. If the
7741 * method cannot be invoked or if it raises an exception, sets \p error
7745 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7749 MonoMethod *method = prepare_to_string_method (obj, &target);
7750 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7754 * mono_object_try_to_string:
7755 * \param obj The object
7756 * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7757 * \param error Set if method cannot be invoked.
7758 * \returns the result of calling \c ToString() on an object. If the
7759 * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7763 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7768 MonoMethod *method = prepare_to_string_method (obj, &target);
7769 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7775 get_native_backtrace (MonoException *exc_raw)
7777 HANDLE_FUNCTION_ENTER ();
7778 MONO_HANDLE_DCL(MonoException, exc);
7779 char * trace = mono_exception_handle_get_native_backtrace (exc);
7780 HANDLE_FUNCTION_RETURN_VAL (trace);
7784 * mono_print_unhandled_exception:
7785 * \param exc The exception
7786 * Prints the unhandled exception.
7789 mono_print_unhandled_exception (MonoObject *exc)
7791 MONO_REQ_GC_UNSAFE_MODE;
7794 char *message = (char*)"";
7795 gboolean free_message = FALSE;
7798 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7799 message = g_strdup ("OutOfMemoryException");
7800 free_message = TRUE;
7801 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7802 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7803 free_message = TRUE;
7806 if (((MonoException*)exc)->native_trace_ips) {
7807 message = get_native_backtrace ((MonoException*)exc);
7808 free_message = TRUE;
7810 MonoObject *other_exc = NULL;
7811 str = mono_object_try_to_string (exc, &other_exc, &error);
7812 if (other_exc == NULL && !is_ok (&error))
7813 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7815 mono_error_cleanup (&error);
7817 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7818 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7820 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7821 original_backtrace, nested_backtrace);
7823 g_free (original_backtrace);
7824 g_free (nested_backtrace);
7825 free_message = TRUE;
7827 message = mono_string_to_utf8_checked (str, &error);
7828 if (!mono_error_ok (&error)) {
7829 mono_error_cleanup (&error);
7830 message = (char *) "";
7832 free_message = TRUE;
7839 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7840 * exc->vtable->klass->name, message);
7842 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7849 * mono_delegate_ctor_with_method:
7850 * \param this pointer to an uninitialized delegate object
7851 * \param target target object
7852 * \param addr pointer to native code
7853 * \param method method
7854 * \param error set on error.
7855 * Initialize a delegate and sets a specific method, not the one
7856 * associated with \p addr. This is useful when sharing generic code.
7857 * In that case \p addr will most probably not be associated with the
7858 * correct instantiation of the method.
7859 * On failure returns FALSE and sets \p error.
7862 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7864 MONO_REQ_GC_UNSAFE_MODE;
7867 MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7869 g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7872 MonoClass *klass = mono_handle_class (this_obj);
7873 g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7876 MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7878 UnlockedIncrement (&mono_stats.delegate_creations);
7880 #ifndef DISABLE_REMOTING
7881 if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7883 method = mono_marshal_get_remoting_invoke (method);
7884 #ifdef ENABLE_INTERPRETER
7885 //g_error ("need RuntimeMethod in method_ptr when using interpreter");
7887 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7888 return_val_if_nok (error, FALSE);
7889 MONO_HANDLE_SET (delegate, target, target);
7893 MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7894 MONO_HANDLE_SET (delegate, target, target);
7897 MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7898 if (callbacks.init_delegate)
7899 callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7904 * mono_delegate_ctor:
7905 * \param this pointer to an uninitialized delegate object
7906 * \param target target object
7907 * \param addr pointer to native code
7908 * \param error set on error.
7909 * This is used to initialize a delegate.
7910 * On failure returns FALSE and sets \p error.
7913 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7915 MONO_REQ_GC_UNSAFE_MODE;
7918 MonoDomain *domain = mono_domain_get ();
7920 MonoMethod *method = NULL;
7924 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7926 if (!ji && domain != mono_get_root_domain ())
7927 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7929 method = mono_jit_info_get_method (ji);
7930 g_assert (!mono_class_is_gtd (method->klass));
7933 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7937 * mono_method_call_message_new:
7938 * \param method method to encapsulate
7939 * \param params parameters to the method
7940 * \param invoke optional, delegate invoke.
7941 * \param cb async callback delegate.
7942 * \param state state passed to the async callback.
7943 * \param error set on error.
7944 * Translates arguments pointers into a \c MonoMethodMessage.
7945 * On failure returns NULL and sets \p error.
7948 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7949 MonoDelegate **cb, MonoObject **state, MonoError *error)
7951 MONO_REQ_GC_UNSAFE_MODE;
7955 MonoDomain *domain = mono_domain_get ();
7956 MonoMethodSignature *sig = mono_method_signature (method);
7957 MonoMethodMessage *msg;
7960 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7961 return_val_if_nok (error, NULL);
7964 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7965 return_val_if_nok (error, NULL);
7966 mono_message_init (domain, msg, rm, NULL, error);
7967 return_val_if_nok (error, NULL);
7968 count = sig->param_count - 2;
7970 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7971 return_val_if_nok (error, NULL);
7972 mono_message_init (domain, msg, rm, NULL, error);
7973 return_val_if_nok (error, NULL);
7974 count = sig->param_count;
7977 for (i = 0; i < count; i++) {
7982 if (sig->params [i]->byref)
7983 vpos = *((gpointer *)params [i]);
7987 klass = mono_class_from_mono_type (sig->params [i]);
7989 if (klass->valuetype) {
7990 arg = mono_value_box_checked (domain, klass, vpos, error);
7991 return_val_if_nok (error, NULL);
7993 arg = *((MonoObject **)vpos);
7995 mono_array_setref (msg->args, i, arg);
7998 if (cb != NULL && state != NULL) {
7999 *cb = *((MonoDelegate **)params [i]);
8001 *state = *((MonoObject **)params [i]);
8008 * mono_method_return_message_restore:
8010 * Restore results from message based processing back to arguments pointers
8013 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8015 MONO_REQ_GC_UNSAFE_MODE;
8019 MonoMethodSignature *sig = mono_method_signature (method);
8020 int i, j, type, size, out_len;
8022 if (out_args == NULL)
8024 out_len = mono_array_length (out_args);
8028 for (i = 0, j = 0; i < sig->param_count; i++) {
8029 MonoType *pt = sig->params [i];
8034 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8038 arg = (char *)mono_array_get (out_args, gpointer, j);
8041 g_assert (type != MONO_TYPE_VOID);
8043 if (MONO_TYPE_IS_REFERENCE (pt)) {
8044 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8047 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8048 size = mono_class_value_size (klass, NULL);
8049 if (klass->has_references)
8050 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8052 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8054 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8055 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8064 #ifndef DISABLE_REMOTING
8067 * mono_load_remote_field:
8068 * \param this pointer to an object
8069 * \param klass klass of the object containing \p field
8070 * \param field the field to load
8071 * \param res a storage to store the result
8072 * This method is called by the runtime on attempts to load fields of
8073 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8074 * the object containing \p field. \p res is a storage location which can be
8075 * used to store the result.
8076 * \returns an address pointing to the value of field.
8079 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8082 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8083 mono_error_cleanup (&error);
8088 * mono_load_remote_field_checked:
8089 * \param this pointer to an object
8090 * \param klass klass of the object containing \p field
8091 * \param field the field to load
8092 * \param res a storage to store the result
8093 * \param error set on error
8094 * This method is called by the runtime on attempts to load fields of
8095 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8096 * the object containing \p field. \p res is a storage location which can be
8097 * used to store the result.
8098 * \returns an address pointing to the value of field. On failure returns NULL and sets \p error.
8101 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8103 MONO_REQ_GC_UNSAFE_MODE;
8105 static MonoMethod *getter = NULL;
8109 MonoDomain *domain = mono_domain_get ();
8110 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8111 MonoClass *field_class;
8112 MonoMethodMessage *msg;
8113 MonoArray *out_args;
8117 g_assert (mono_object_is_transparent_proxy (this_obj));
8118 g_assert (res != NULL);
8120 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8121 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8126 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8128 mono_error_set_not_supported (error, "Linked away.");
8133 field_class = mono_class_from_mono_type (field->type);
8135 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8136 return_val_if_nok (error, NULL);
8137 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8138 return_val_if_nok (error, NULL);
8139 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8140 return_val_if_nok (error, NULL);
8141 mono_message_init (domain, msg, rm, out_args, error);
8142 return_val_if_nok (error, NULL);
8144 full_name = mono_type_get_full_name (klass);
8145 MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8147 return_val_if_nok (error, NULL);
8148 mono_array_setref (msg->args, 0, full_name_str);
8149 MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8150 return_val_if_nok (error, NULL);
8151 mono_array_setref (msg->args, 1, field_name);
8153 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8154 return_val_if_nok (error, NULL);
8157 mono_error_set_exception_instance (error, (MonoException *)exc);
8161 if (mono_array_length (out_args) == 0)
8164 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8166 if (field_class->valuetype) {
8167 return ((char *)*res) + sizeof (MonoObject);
8173 * mono_load_remote_field_new:
8177 * Missing documentation.
8180 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8184 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8185 mono_error_cleanup (&error);
8190 * mono_load_remote_field_new_checked:
8191 * \param this pointer to an object
8192 * \param klass klass of the object containing \p field
8193 * \param field the field to load
8194 * \param error set on error.
8195 * This method is called by the runtime on attempts to load fields of
8196 * transparent proxy objects. \p this points to such TP, \p klass is the class of
8197 * the object containing \p field.
8198 * \returns a freshly allocated object containing the value of the field. On failure returns NULL and sets \p error.
8201 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8203 MONO_REQ_GC_UNSAFE_MODE;
8207 static MonoMethod *tp_load = NULL;
8209 g_assert (mono_object_is_transparent_proxy (this_obj));
8212 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8214 mono_error_set_not_supported (error, "Linked away.");
8219 /* MonoType *type = mono_class_get_type (klass); */
8225 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8229 * mono_store_remote_field:
8230 * \param this_obj pointer to an object
8231 * \param klass klass of the object containing \p field
8232 * \param field the field to load
8233 * \param val the value/object to store
8234 * This method is called by the runtime on attempts to store fields of
8235 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8236 * the object containing \p field. \p val is the new value to store in \p field.
8239 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8242 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8243 mono_error_cleanup (&error);
8247 * mono_store_remote_field_checked:
8248 * \param this_obj pointer to an object
8249 * \param klass klass of the object containing \p field
8250 * \param field the field to load
8251 * \param val the value/object to store
8252 * \param error set on error
8253 * This method is called by the runtime on attempts to store fields of
8254 * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8255 * the object containing \p field. \p val is the new value to store in \p field.
8256 * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8259 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8262 MONO_REQ_GC_UNSAFE_MODE;
8266 MonoDomain *domain = mono_domain_get ();
8267 MonoClass *field_class;
8270 g_assert (mono_object_is_transparent_proxy (this_obj));
8272 field_class = mono_class_from_mono_type (field->type);
8274 if (field_class->valuetype) {
8275 arg = mono_value_box_checked (domain, field_class, val, error);
8276 return_val_if_nok (error, FALSE);
8278 arg = *((MonoObject**)val);
8281 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8285 * mono_store_remote_field_new:
8290 * Missing documentation
8293 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8296 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8297 mono_error_cleanup (&error);
8301 * mono_store_remote_field_new_checked:
8307 * Missing documentation
8310 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8312 MONO_REQ_GC_UNSAFE_MODE;
8314 static MonoMethod *tp_store = NULL;
8318 g_assert (mono_object_is_transparent_proxy (this_obj));
8321 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8323 mono_error_set_not_supported (error, "Linked away.");
8333 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8334 return is_ok (error);
8339 * mono_create_ftnptr:
8341 * Given a function address, create a function descriptor for it.
8342 * This is only needed on some platforms.
8345 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8347 return callbacks.create_ftnptr (domain, addr);
8351 * mono_get_addr_from_ftnptr:
8353 * Given a pointer to a function descriptor, return the function address.
8354 * This is only needed on some platforms.
8357 mono_get_addr_from_ftnptr (gpointer descr)
8359 return callbacks.get_addr_from_ftnptr (descr);
8363 * mono_string_chars:
8364 * \param s a \c MonoString
8365 * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8368 mono_string_chars (MonoString *s)
8370 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8376 * mono_string_length:
8377 * \param s MonoString
8378 * \returns the length in characters of the string
8381 mono_string_length (MonoString *s)
8383 MONO_REQ_GC_UNSAFE_MODE;
8389 * mono_string_handle_length:
8390 * \param s \c MonoString
8391 * \returns the length in characters of the string
8394 mono_string_handle_length (MonoStringHandle s)
8396 MONO_REQ_GC_UNSAFE_MODE;
8398 return MONO_HANDLE_GETVAL (s, length);
8403 * mono_array_length:
8404 * \param array a \c MonoArray*
8405 * \returns the total number of elements in the array. This works for
8406 * both vectors and multidimensional arrays.
8409 mono_array_length (MonoArray *array)
8411 MONO_REQ_GC_UNSAFE_MODE;
8413 return array->max_length;
8417 * mono_array_addr_with_size:
8418 * \param array a \c MonoArray*
8419 * \param size size of the array elements
8420 * \param idx index into the array
8421 * Use this function to obtain the address for the \p idx item on the
8422 * \p array containing elements of size \p size.
8424 * This method performs no bounds checking or type checking.
8425 * \returns the address of the \p idx element in the array.
8428 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8430 MONO_REQ_GC_UNSAFE_MODE;
8432 return ((char*)(array)->vector) + size * idx;
8437 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8439 MonoDomain *domain = mono_domain_get ();
8447 len = g_list_length (list);
8448 res = mono_array_new_checked (domain, eclass, len, error);
8449 return_val_if_nok (error, NULL);
8451 for (i = 0; list; list = list->next, i++)
8452 mono_array_set (res, gpointer, i, list->data);
8459 * The following section is purely to declare prototypes and
8460 * document the API, as these C files are processed by our
8466 * \param array array to alter
8467 * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8468 * \param index index into the array
8469 * \param value value to set
8470 * Value Type version: This sets the \p index's element of the \p array
8471 * with elements of size sizeof(type) to the provided \p value.
8473 * This macro does not attempt to perform type checking or bounds checking.
8475 * Use this to set value types in a \c MonoArray.
8477 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8482 * mono_array_setref:
8483 * \param array array to alter
8484 * \param index index into the array
8485 * \param value value to set
8486 * Reference Type version. This sets the \p index's element of the
8487 * \p array with elements of size sizeof(type) to the provided \p value.
8489 * This macro does not attempt to perform type checking or bounds checking.
8491 * Use this to reference types in a \c MonoArray.
8493 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8499 * \param array array on which to operate on
8500 * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8501 * \param index index into the array
8503 * Use this macro to retrieve the \p index element of an \p array and
8504 * extract the value assuming that the elements of the array match
8505 * the provided type value.
8507 * This method can be used with both arrays holding value types and
8508 * reference types. For reference types, the \p type parameter should
8509 * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8511 * This macro does not attempt to perform type checking or bounds checking.
8513 * \returns The element at the \p index position in the \p array.
8515 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)